feat(i18n): add French translation (#257)

Co-authored-by: Romain BARAUD <romain.baraud@gmail.com>
This commit is contained in:
Romain Baraud
2026-05-21 04:08:35 +02:00
committed by GitHub
parent 8e27658157
commit 459178f283
2 changed files with 250 additions and 2 deletions
+4 -2
View File
@@ -3,8 +3,9 @@
import { createContext, useContext, useState, useCallback, type ReactNode } from 'react';
import en from './translations/en.json';
import zhCN from './translations/zh-CN.json';
import fr from './translations/fr.json';
export type Locale = 'en' | 'zh-CN';
export type Locale = 'en' | 'zh-CN' | 'fr';
/**
* Registry of available locales for the UI language toggle.
@@ -27,9 +28,10 @@ export type Locale = 'en' | 'zh-CN';
export const LOCALES: ReadonlyArray<{ code: Locale; label: string }> = [
{ code: 'en', label: 'English' },
{ code: 'zh-CN', label: '中文 (简体)' },
{ code: 'fr', label: 'Français' },
];
const translations: Record<Locale, Record<string, Record<string, string>>> = { en, 'zh-CN': zhCN };
const translations: Record<Locale, Record<string, Record<string, string>>> = { en, 'zh-CN': zhCN, fr };
function isLocale(value: unknown): value is Locale {
return typeof value === 'string' && LOCALES.some((entry) => entry.code === value);
+246
View File
@@ -0,0 +1,246 @@
{
"brand": {
"title": "S H A D O W B R O K E R",
"subtitle": "INTERCEPTION MONDIALE DES MENACES",
"systemMetrics": "OPTIC VIS:113 SRC:180 DENS:1.42 0.8ms"
},
"nav": {
"layers": "COUCHES",
"intel": "RENSEIGNEMENTS",
"markets": "MARCHÉS",
"dataLayers": "COUCHES DE DONNÉES",
"prioritizingMapFeeds": "PRIORISATION DES FLUX CARTE",
"restoreUi": "RESTAURER L'INTERFACE"
},
"controls": {
"updates": "MISES À JOUR",
"checking": "VÉRIFICATION...",
"upToDate": "À JOUR",
"checkFailed": "VÉRIFICATION ÉCHOUÉE",
"node": "NŒUD",
"terminal": "TERMINAL",
"coordinates": "COORDONNÉES",
"location": "LOCALISATION",
"style": "STYLE",
"solar": "SOLAIRE",
"hoverMap": "Survolez la carte...",
"na": "N/A"
},
"update": {
"downloadInstaller": "TÉLÉCHARGER L'INSTALLATEUR",
"installUpdate": "INSTALLER LA MISE À JOUR",
"autoUpdate": "MISE À JOUR AUTO",
"viewRelease": "VOIR LA VERSION",
"manualDownload": "TÉLÉCHARGEMENT MANUEL",
"cancel": "ANNULER",
"tryAgain": "RÉESSAYER",
"downloadingUpdate": "TÉLÉCHARGEMENT DE LA MISE À JOUR...",
"restarting": "REDÉMARRAGE...",
"updateFailed": "MISE À JOUR ÉCHOUÉE",
"dockerUpdate": "MISE À JOUR DOCKER",
"dockerUpdateDetail": "Les conteneurs Docker doivent être mis à jour en tirant de nouvelles images.\n Exécutez ceci sur votre machine hôte :"
},
"node": {
"activateNode": "ACTIVER LE NŒUD",
"activatingNode": "ACTIVATION DU NŒUD",
"nodeActivated": "NŒUD ACTIVÉ",
"stipulations": "CONDITIONS",
"yes": "OUI",
"no": "NON",
"agree": "ACCEPTER",
"disagree": "REFUSER",
"turnOff": "DÉSACTIVER",
"keepOn": "GARDER ACTIVÉ",
"turningOff": "DÉSACTIVATION...",
"activating": "ACTIVATION...",
"nodeOnline": "NŒUD EN LIGNE",
"generatingIdentity": "Génération de l'identité...",
"identityReady": "Identité prête",
"preparingTransport": "Préparation du transport onion...",
"findingPeers": "Recherche de pairs d'amorçage...",
"peersReady": "Pairs d'amorçage prêts",
"syncingChain": "Synchronisation de la chaîne...",
"soloNodeReady": "Nœud solo prêt",
"synced": "Synchronisé",
"events": "événements",
"peers": "pairs",
"close": "FERMER",
"activatePrompt": "Voulez-vous activer un nœud sur cette installation ?",
"activateDetail": "Cela active votre nœud participant local et synchronise l'Infonet uniquement via les pairs onion/RNS Wormhole disponibles. L'amorçage par clearnet est désactivé par défaut.",
"keepSyncing": "Votre nœud continue de se synchroniser tant que le backend est en cours d'exécution — vous pouvez fermer cet onglet de navigateur. Pour exécuter un nœud headless sans le tableau de bord, utilisez",
"termsTitle": "EN CONTINUANT VOUS ACCEPTEZ :",
"term1": "Cette installation peut conserver une copie locale de la chaîne Infonet publique.",
"term2": "Les nouvelles installations n'utilisent pas de seed Infonet clearnet.",
"term3": "La synchronisation du nœud participant nécessite un pair onion/RNS via Wormhole.",
"term4": "Votre backend peut se synchroniser avec des pairs d'amorçage privés configurés en arrière-plan.",
"term5": "Wormhole maintient l'Infonet, les gates, le Dead Drop et le trafic DM sur la voie obfusquée.",
"syncTakingLong": "La synchronisation prend plus de temps que prévu. Votre nœud est actif et continuera à se synchroniser en arrière-plan."
},
"terminal": {
"infonetTerminal": "TERMINAL INFONET",
"privateLaneReady": "VOIE PRIVÉE PRÊTE",
"privateLaneStarting": "VOIE PRIVÉE DÉMARRAGE",
"privateLaneOffline": "VOIE PRIVÉE HORS LIGNE",
"enterTerminal": "Entrer dans le terminal Wormhole et se synchroniser avec les communs obfusqués de l'Infonet ?",
"terminalDetail": "Le terminal fonctionne via Wormhole pour les gates obfusqués, la boîte de réception et les communications expérimentales.",
"identityReady": "Votre identité obfusquée est déjà provisionnée. Entrer maintenant maintient la voie obfusquée séparée du chemin de synchronisation du nœud public.",
"identityNotReady": "Cela active Wormhole et ouvre la voie obfusquée. Si vous avez déjà une identité Wormhole, elle sera réutilisée. Si vous n'en avez pas, une sera amorcée une fois puis conservée.",
"beforeYouEnter": "AVANT D'ENTRER :",
"termTerminal1": "Le terminal est destiné aux gates Wormhole (voie privée transitoire) et au Dead Drop / DM (voie privée renforcée).",
"termTerminal2": "Votre nœud participant peut rester actif séparément sans modifier cette voie d'identité obfusquée.",
"termTerminal3": "Mesh reste le périmètre public. Wormhole est le commun obfusqué.",
"wormholeCleanup": "NETTOYAGE WORMHOLE :",
"cleanupDetail": "Fermer le terminal Infonet arrêtera Wormhole automatiquement. Si vous forcez la fermeture du navigateur ou si l'arrêt échoue, Wormhole peut continuer à tourner en arrière-plan. Exécutez",
"cleanupFromRoot": "depuis la racine du projet pour vous assurer qu'il est complètement arrêté.",
"enterWormhole": "ENTRER DANS WORMHOLE",
"activateWormhole": "ACTIVER WORMHOLE",
"entering": "ENTRÉE...",
"goToMesh": "ALLER AU MESH"
},
"status": {
"off": "ARRÊTÉ",
"solo": "SOLO",
"connected": "CONNECTÉ",
"syncing": "SYNCHRONISATION",
"forkStop": "ARRÊT FOURCHE",
"syncIssue": "PROBLÈME DE SYNC",
"active": "ACTIF",
"participant": "participant",
"nodeOff": "nœud • arrêté",
"bootstrapWarning": "nœud • avertissement de démarrage"
},
"backend": {
"offline": "BACKEND HORS LIGNE — Impossible de joindre le serveur backend. Vérifiez que le conteneur backend est en cours d'exécution et que BACKEND_URL est correct."
},
"settings": {
"title": "Paramètres",
"close": "Fermer",
"general": "Général",
"feeds": "Flux",
"shodan": "Shodan",
"sar": "SAR",
"infonet": "Infonet",
"about": "À propos"
},
"legend": {
"title": "Légende",
"close": "Fermer"
},
"onboarding": {
"welcome": "Bienvenue dans ShadowBroker",
"getStarted": "Commencer"
},
"news": {
"title": "Renseignement Actualités",
"noResults": "Aucun résultat",
"searchPlaceholder": "Rechercher des actualités..."
},
"filters": {
"title": "Filtres de données",
"clear": "Effacer",
"all": "Tout"
},
"map": {
"findLocate": "Rechercher / Localiser",
"searchPlaceholder": "Rechercher coordonnées, lieu ou indicatif...",
"measure": "Mesurer",
"clearMeasure": "Effacer la mesure"
},
"layers": {
"aircraft": "Aéronefs",
"commercialFlights": "Vols commerciaux",
"privateAircraft": "Aéronefs privés",
"privateJets": "Jets privés",
"militaryFlights": "Vols militaires",
"trackedAircraft": "Aéronefs suivis",
"gpsJamming": "Brouillage GPS",
"maritime": "Maritime",
"militaryVessels": "Navires militaires",
"cargoShips": "Navires de charge",
"civilianShips": "Navires civils",
"passengerShips": "Navires à passagers",
"trackedYachts": "Yachts suivis",
"fishingActivity": "Activité de pêche",
"space": "Espace",
"satellites": "Satellites",
"gibsImagery": "Imagerie GIBS",
"highresSatellite": "Satellite haute résolution",
"sentinelHub": "Sentinel Hub",
"viirsNightlights": "Éclairage nocturne VIIRS",
"hazards": "Dangers",
"earthquakes": "Séismes",
"fires": "Incendies",
"ukraineAlerts": "Alertes Ukraine",
"weatherAlerts": "Alertes météo",
"volcanoes": "Volcans",
"airQuality": "Qualité de l'air",
"infrastructure": "Infrastructure",
"cctv": "CCTV",
"datacenters": "Centres de données",
"internetOutages": "Pannes Internet",
"powerPlants": "Centrales électriques",
"militaryBases": "Bases militaires",
"trains": "Trains",
"sigint": "SIGINT",
"kiwisdr": "KiwiSDR",
"pskReporter": "PSK Reporter",
"satnogs": "SatNOGS",
"tinygs": "TinyGS",
"scanners": "Scanners",
"meshtastic": "Meshtastic",
"aprs": "APRS",
"overlays": "Couches superposées",
"ukraineFrontline": "Ligne de front Ukraine",
"globalIncidents": "Incidents mondiaux",
"dayNight": "Jour/Nuit",
"correlations": "Corrélations",
"contradictions": "Contradictions",
"uapSightings": "Observations de PAN",
"biosurveillance": "Biosurveillance",
"wastewater": "Eaux usées",
"crowdThreat": "CrowdThreat",
"shodanOverlay": "Couche Shodan",
"aiIntel": "Infos IA",
"sar": "SAR"
},
"shodan": {
"title": "Connecteur Shodan",
"searchPlaceholder": "Rechercher des appareils...",
"apiKeyRequired": "Clé API requise",
"results": "résultats"
},
"ai": {
"title": "Panneau d'infos IA",
"connected": "Connecté",
"disconnected": "Déconnecté"
},
"meshChat": {
"title": "Chat Mesh",
"infonet": "Infonet",
"meshtastic": "Meshtastic",
"deadDrop": "Dead Drop",
"sendMessage": "Envoyer un message",
"placeholder": "Tapez un message..."
},
"watchlist": {
"title": "Liste de surveillance",
"empty": "Aucun élément surveillé",
"clear": "Effacer"
},
"timeline": {
"title": "Chronologie des événements",
"noEvents": "Aucun événement"
},
"sar": {
"title": "Détection de changements au sol SAR",
"modeA": "Mode Catalogue",
"modeB": "Mode Anomalie",
"aoiEditor": "Éditeur AOI",
"addAoi": "Ajouter AOI",
"groundDeformation": "Déformation du sol",
"waterChange": "Changement hydrique",
"vegetation": "Perturbation végétale",
"damage": "Évaluation des dégâts",
"coherence": "Changement de cohérence"
}
}