From 9a65532a50c96d5e609c7d0cf0c61a0632a7a52c Mon Sep 17 00:00:00 2001 From: comeback01 Date: Fri, 12 Sep 2025 08:27:05 +0200 Subject: [PATCH] feat: add french localization (#337) Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- frontend/src/components/CloudServerDetail.tsx | 4 +- frontend/src/components/ServerForm.tsx | 20 +- frontend/src/components/icons/DiscordIcon.tsx | 4 +- frontend/src/components/icons/GitHubIcon.tsx | 4 +- frontend/src/components/icons/SponsorIcon.tsx | 4 +- frontend/src/components/icons/WeChatIcon.tsx | 4 +- frontend/src/components/ui/LanguageSwitch.tsx | 3 +- frontend/src/components/ui/Toast.tsx | 5 +- frontend/src/i18n.ts | 4 + locales/en.json | 20 +- locales/fr.json | 621 ++++++++++++++++++ locales/zh.json | 20 +- 12 files changed, 691 insertions(+), 22 deletions(-) create mode 100644 locales/fr.json diff --git a/frontend/src/components/CloudServerDetail.tsx b/frontend/src/components/CloudServerDetail.tsx index 5179aca..df99e19 100644 --- a/frontend/src/components/CloudServerDetail.tsx +++ b/frontend/src/components/CloudServerDetail.tsx @@ -231,8 +231,8 @@ const CloudServerDetail: React.FC = ({ className="w-full border rounded-md px-3 py-2 border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 form-input" > - - + + ); } else if (propSchema.type === 'number' || propSchema.type === 'integer') { diff --git a/frontend/src/components/ServerForm.tsx b/frontend/src/components/ServerForm.tsx index e46014d..65099e4 100644 --- a/frontend/src/components/ServerForm.tsx +++ b/frontend/src/components/ServerForm.tsx @@ -306,7 +306,7 @@ const ServerForm = ({ onSubmit, onCancel, initialData = null, modalTitle, formEr onChange={() => updateServerType('stdio')} className="mr-1" /> - +
updateServerType('sse')} className="mr-1" /> - +
updateServerType('streamable-http')} className="mr-1" /> - +
updateServerType('openapi')} className="mr-1" /> - +
@@ -500,9 +500,9 @@ const ServerForm = ({ onSubmit, onCancel, initialData = null, modalTitle, formEr }))} className="w-full border rounded px-2 py-1 text-sm focus:outline-none form-input" > - - - + + +
@@ -537,9 +537,9 @@ const ServerForm = ({ onSubmit, onCancel, initialData = null, modalTitle, formEr }))} className="w-full border rounded px-2 py-1 text-sm focus:outline-none form-input" > - - - + + +
diff --git a/frontend/src/components/icons/DiscordIcon.tsx b/frontend/src/components/icons/DiscordIcon.tsx index b21e16d..b0a9298 100644 --- a/frontend/src/components/icons/DiscordIcon.tsx +++ b/frontend/src/components/icons/DiscordIcon.tsx @@ -1,6 +1,8 @@ import React from 'react'; +import { useTranslation } from 'react-i18next'; export const DiscordIcon: React.FC> = (props) => { + const { t } = useTranslation(); return ( > = (props) => { fill="currentColor" {...props} > - Discord + {t('common.discord')} ); diff --git a/frontend/src/components/icons/GitHubIcon.tsx b/frontend/src/components/icons/GitHubIcon.tsx index afc9eb5..107b2be 100644 --- a/frontend/src/components/icons/GitHubIcon.tsx +++ b/frontend/src/components/icons/GitHubIcon.tsx @@ -1,6 +1,8 @@ import React from 'react'; +import { useTranslation } from 'react-i18next'; export const GitHubIcon: React.FC> = (props) => { + const { t } = useTranslation(); return ( > = (props) => { fill="currentColor" {...props} > - GitHub + {t('common.github')} ); diff --git a/frontend/src/components/icons/SponsorIcon.tsx b/frontend/src/components/icons/SponsorIcon.tsx index 0facfe0..8f7988e 100644 --- a/frontend/src/components/icons/SponsorIcon.tsx +++ b/frontend/src/components/icons/SponsorIcon.tsx @@ -1,6 +1,8 @@ import React from 'react'; +import { useTranslation } from 'react-i18next'; export const SponsorIcon: React.FC> = (props) => { + const { t } = useTranslation(); return ( > = (props) => { fill="currentColor" {...props} > - Sponsor + {t('sponsor.label')} ); diff --git a/frontend/src/components/icons/WeChatIcon.tsx b/frontend/src/components/icons/WeChatIcon.tsx index 7e51a0b..e0b0bc6 100644 --- a/frontend/src/components/icons/WeChatIcon.tsx +++ b/frontend/src/components/icons/WeChatIcon.tsx @@ -1,6 +1,8 @@ import React from 'react'; +import { useTranslation } from 'react-i18next'; export const WeChatIcon: React.FC> = (props) => { + const { t } = useTranslation(); return ( > = (props) => { fill="currentColor" {...props} > - WeChat + {t('common.wechat')} ); diff --git a/frontend/src/components/ui/LanguageSwitch.tsx b/frontend/src/components/ui/LanguageSwitch.tsx index f3b42c2..59bc4b1 100644 --- a/frontend/src/components/ui/LanguageSwitch.tsx +++ b/frontend/src/components/ui/LanguageSwitch.tsx @@ -10,7 +10,8 @@ const LanguageSwitch: React.FC = () => { // Available languages const availableLanguages = [ { code: 'en', label: 'English' }, - { code: 'zh', label: '中文' } + { code: 'zh', label: '中文' }, + { code: 'fr', label: 'Français' } ]; // Update current language when it changes diff --git a/frontend/src/components/ui/Toast.tsx b/frontend/src/components/ui/Toast.tsx index 31ad521..752be28 100644 --- a/frontend/src/components/ui/Toast.tsx +++ b/frontend/src/components/ui/Toast.tsx @@ -1,4 +1,5 @@ import React, { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Check, X } from 'lucide-react'; import { cn } from '@/utils/cn'; @@ -19,6 +20,8 @@ const Toast: React.FC = ({ onClose, visible }) => { + const { t } = useTranslation(); + useEffect(() => { if (visible) { const timer = setTimeout(() => { @@ -83,7 +86,7 @@ const Toast: React.FC = ({ `hover:bg-${type}-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-${type}-500` )} > - Dismiss + {t('common.dismiss')}
diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts index 6840055..4148afa 100644 --- a/frontend/src/i18n.ts +++ b/frontend/src/i18n.ts @@ -5,6 +5,7 @@ import LanguageDetector from 'i18next-browser-languagedetector'; // Import shared translations from root locales directory import enTranslation from '../../locales/en.json'; import zhTranslation from '../../locales/zh.json'; +import frTranslation from '../../locales/fr.json'; i18n // Detect user language @@ -20,6 +21,9 @@ i18n zh: { translation: zhTranslation, }, + fr: { + translation: frTranslation, + }, }, fallbackLng: 'en', debug: process.env.NODE_ENV === 'development', diff --git a/locales/en.json b/locales/en.json index 175c0df..9c824c0 100644 --- a/locales/en.json +++ b/locales/en.json @@ -93,6 +93,10 @@ "updateError": "Failed to update server", "editTitle": "Edit Server: {{serverName}}", "type": "Server Type", + "typeStdio": "STDIO", + "typeSse": "SSE", + "typeStreamableHttp": "Streamable HTTP", + "typeOpenapi": "OpenAPI", "command": "Command", "arguments": "Arguments", "envVars": "Environment Variables", @@ -145,11 +149,17 @@ "httpAuthConfig": "HTTP Authentication Configuration", "httpScheme": "Authentication Scheme", "httpCredentials": "Credentials", + "httpSchemeBasic": "Basic", + "httpSchemeBearer": "Bearer", + "httpSchemeDigest": "Digest", "oauth2Config": "OAuth 2.0 Configuration", "oauth2Token": "Access Token", "openIdConnectConfig": "OpenID Connect Configuration", "openIdConnectUrl": "Discovery URL", - "openIdConnectToken": "ID Token" + "openIdConnectToken": "ID Token", + "apiKeyInHeader": "Header", + "apiKeyInQuery": "Query", + "apiKeyInCookie": "Cookie" } }, "status": { @@ -190,7 +200,13 @@ "copyFailed": "Copy failed", "close": "Close", "confirm": "Confirm", - "language": "Language" + "language": "Language", + "true": "True", + "false": "False", + "dismiss": "Dismiss", + "github": "GitHub", + "wechat": "WeChat", + "discord": "Discord" }, "nav": { "dashboard": "Dashboard", diff --git a/locales/fr.json b/locales/fr.json new file mode 100644 index 0000000..40e1d22 --- /dev/null +++ b/locales/fr.json @@ -0,0 +1,621 @@ +{ + "app": { + "title": "Tableau de bord MCPHub", + "error": "Erreur", + "closeButton": "Fermer", + "noServers": "Aucun serveur MCP disponible", + "loading": "Chargement...", + "logout": "Déconnexion", + "profile": "Profil", + "changePassword": "Changer le mot de passe", + "toggleSidebar": "Basculer la barre latérale", + "welcomeUser": "Bienvenue, {{username}}", + "name": "MCPHub" + }, + "about": { + "title": "À propos", + "versionInfo": "Version MCPHub : {{version}}", + "newVersion": "Nouvelle version disponible !", + "currentVersion": "Version actuelle", + "newVersionAvailable": "La nouvelle version {{version}} est disponible", + "viewOnGitHub": "Voir sur GitHub", + "checkForUpdates": "Vérifier les mises à jour", + "checking": "Vérification des mises à jour..." + }, + "profile": { + "viewProfile": "Voir le profil", + "userCenter": "Centre utilisateur" + }, + "sponsor": { + "label": "Sponsor", + "title": "Soutenir le projet", + "rewardAlt": "QR Code de récompense", + "supportMessage": "Soutenez le développement de MCPHub en m'offrant un café !", + "supportButton": "Soutenir sur Ko-fi" + }, + "wechat": { + "label": "WeChat", + "title": "Se connecter via WeChat", + "qrCodeAlt": "QR Code WeChat", + "scanMessage": "Scannez ce QR code pour nous contacter sur WeChat" + }, + "discord": { + "label": "Discord", + "title": "Rejoignez notre serveur Discord", + "community": "Rejoignez notre communauté grandissante sur Discord pour du support, des discussions et des mises à jour !" + }, + "theme": { + "title": "Thème", + "light": "Clair", + "dark": "Sombre", + "system": "Système" + }, + "auth": { + "login": "Connexion", + "loginTitle": "Se connecter à MCPHub", + "slogan": "Le Hub unifié pour les serveurs MCP", + "subtitle": "Plateforme de gestion centralisée pour les serveurs Model Context Protocol. Organisez, surveillez et mettez à l'échelle plusieurs serveurs MCP avec des stratégies de routage flexibles.", + "username": "Nom d'utilisateur", + "password": "Mot de passe", + "loggingIn": "Connexion en cours...", + "emptyFields": "Le nom d'utilisateur et le mot de passe ne peuvent pas être vides", + "loginFailed": "Échec de la connexion, veuillez vérifier votre nom d'utilisateur et votre mot de passe", + "loginError": "Une erreur est survenue lors de la connexion", + "currentPassword": "Mot de passe actuel", + "newPassword": "Nouveau mot de passe", + "confirmPassword": "Confirmer le mot de passe", + "passwordsNotMatch": "Le nouveau mot de passe et la confirmation ne correspondent pas", + "changePasswordSuccess": "Mot de passe changé avec succès", + "changePasswordError": "Échec du changement de mot de passe", + "changePassword": "Changer le mot de passe", + "passwordChanged": "Mot de passe changé avec succès", + "passwordChangeError": "Échec du changement de mot de passe" + }, + "server": { + "addServer": "Ajouter un serveur", + "add": "Ajouter", + "edit": "Modifier", + "delete": "Supprimer", + "confirmDelete": "Êtes-vous sûr de vouloir supprimer ce serveur ?", + "deleteWarning": "La suppression du serveur '{{name}}' le supprimera ainsi que toutes ses données. Cette action est irréversible.", + "status": "Statut", + "tools": "Outils", + "prompts": "Invites", + "name": "Nom du serveur", + "url": "URL du serveur", + "apiKey": "Clé API", + "save": "Enregistrer", + "cancel": "Annuler", + "invalidConfig": "Impossible de trouver les données de configuration pour {{serverName}}", + "addError": "Échec de l'ajout du serveur", + "editError": "Échec de la modification du serveur {{serverName}}", + "deleteError": "Échec de la suppression du serveur {{serverName}}", + "updateError": "Échec de la mise à jour du serveur", + "editTitle": "Modifier le serveur : {{serverName}}", + "type": "Type de serveur", + "typeStdio": "STDIO", + "typeSse": "SSE", + "typeStreamableHttp": "HTTP diffusable", + "typeOpenapi": "OpenAPI", + "command": "Commande", + "arguments": "Arguments", + "envVars": "Variables d'environnement", + "headers": "En-têtes HTTP", + "key": "clé", + "value": "valeur", + "enabled": "Activé", + "enable": "Activer", + "disable": "Désactiver", + "requestOptions": "Configuration", + "timeout": "Délai d'attente de la requête", + "timeoutDescription": "Délai d'attente pour les requêtes vers le serveur MCP (ms)", + "maxTotalTimeout": "Délai d'attente total maximum", + "maxTotalTimeoutDescription": "Délai d'attente total maximum pour les requêtes envoyées au serveur MCP (ms) (à utiliser avec les notifications de progression)", + "resetTimeoutOnProgress": "Réinitialiser le délai d'attente en cas de progression", + "resetTimeoutOnProgressDescription": "Réinitialiser le délai d'attente lors des notifications de progression", + "remove": "Retirer", + "toggleError": "Échec du basculement du serveur {{serverName}}", + "alreadyExists": "Le serveur {{serverName}} existe déjà", + "invalidData": "Données de serveur invalides fournies", + "notFound": "Serveur {{serverName}} non trouvé", + "namePlaceholder": "Entrez le nom du serveur", + "urlPlaceholder": "Entrez l'URL du serveur", + "commandPlaceholder": "Entrez la commande", + "argumentsPlaceholder": "Entrez les arguments", + "errorDetails": "Détails de l'erreur", + "viewErrorDetails": "Voir les détails de l'erreur", + "confirmVariables": "Confirmer la configuration des variables", + "variablesDetected": "Variables détectées dans la configuration. Veuillez confirmer que ces variables sont correctement configurées :", + "detectedVariables": "Variables détectées", + "confirmVariablesMessage": "Veuillez vous assurer que ces variables sont correctement définies dans votre environnement d'exécution. Continuer l'ajout du serveur ?", + "confirmAndAdd": "Confirmer et ajouter", + "openapi": { + "inputMode": "Mode de saisie", + "inputModeUrl": "URL de la spécification", + "inputModeSchema": "Schéma JSON", + "specUrl": "URL de la spécification OpenAPI", + "schema": "Schéma JSON OpenAPI", + "schemaHelp": "Collez votre schéma JSON OpenAPI complet ici", + "security": "Type de sécurité", + "securityNone": "Aucun", + "securityApiKey": "Clé API", + "securityHttp": "Authentification HTTP", + "securityOAuth2": "OAuth 2.0", + "securityOpenIdConnect": "OpenID Connect", + "apiKeyConfig": "Configuration de la clé API", + "apiKeyName": "Nom de l'en-tête/paramètre", + "apiKeyIn": "Emplacement", + "apiKeyValue": "Valeur de la clé API", + "httpAuthConfig": "Configuration de l'authentification HTTP", + "httpScheme": "Schéma d'authentification", + "httpCredentials": "Identifiants", + "httpSchemeBasic": "Basic", + "httpSchemeBearer": "Bearer", + "httpSchemeDigest": "Digest", + "oauth2Config": "Configuration OAuth 2.0", + "oauth2Token": "Jeton d'accès", + "openIdConnectConfig": "Configuration OpenID Connect", + "openIdConnectUrl": "URL de découverte", + "openIdConnectToken": "Jeton d'identification", + "apiKeyInHeader": "En-tête", + "apiKeyInQuery": "Requête", + "apiKeyInCookie": "Cookie" + } + }, + "status": { + "online": "En ligne", + "offline": "Hors ligne", + "connecting": "Connexion en cours" + }, + "errors": { + "general": "Une erreur est survenue", + "network": "Erreur de connexion réseau. Veuillez vérifier votre connexion Internet", + "serverConnection": "Impossible de se connecter au serveur. Veuillez vérifier si le serveur est en cours d'exécution", + "serverAdd": "Échec de l'ajout du serveur. Veuillez vérifier l'état du serveur", + "serverUpdate": "Échec de la modification du serveur {{serverName}}. Veuillez vérifier l'état du serveur", + "serverFetch": "Échec de la récupération des données du serveur. Veuillez réessayer plus tard", + "initialStartup": "Le serveur est peut-être en cours de démarrage. Veuillez patienter un instant car ce processus peut prendre du temps au premier lancement...", + "serverInstall": "Échec de l'installation du serveur", + "failedToFetchSettings": "Échec de la récupération des paramètres", + "failedToUpdateRouteConfig": "Échec de la mise à jour de la configuration de routage", + "failedToUpdateSmartRoutingConfig": "Échec de la mise à jour de la configuration du routage intelligent" + }, + "common": { + "processing": "En cours de traitement...", + "save": "Enregistrer", + "cancel": "Annuler", + "refresh": "Actualiser", + "create": "Créer", + "creating": "Création en cours...", + "update": "Mettre à jour", + "updating": "Mise à jour en cours...", + "submitting": "Envoi en cours...", + "delete": "Supprimer", + "remove": "Retirer", + "copy": "Copier", + "copyId": "Copier l'ID", + "copyUrl": "Copier l'URL", + "copyJson": "Copier le JSON", + "copySuccess": "Copié dans le presse-papiers", + "copyFailed": "Échec de la copie", + "close": "Fermer", + "confirm": "Confirmer", + "language": "Langue", + "true": "Vrai", + "false": "Faux", + "dismiss": "Rejeter", + "github": "GitHub", + "wechat": "WeChat", + "discord": "Discord" + }, + "nav": { + "dashboard": "Tableau de bord", + "servers": "Serveurs", + "groups": "Groupes", + "users": "Utilisateurs", + "settings": "Paramètres", + "changePassword": "Changer le mot de passe", + "market": "Marché", + "cloud": "Marché Cloud", + "logs": "Journaux" + }, + "pages": { + "dashboard": { + "title": "Tableau de bord", + "totalServers": "Total", + "onlineServers": "En ligne", + "offlineServers": "Hors ligne", + "connectingServers": "En connexion", + "recentServers": "Serveurs récents" + }, + "servers": { + "title": "Gestion des serveurs" + }, + "groups": { + "title": "Gestion des groupes" + }, + "users": { + "title": "Gestion des utilisateurs" + }, + "settings": { + "title": "Paramètres", + "language": "Langue", + "account": "Paramètres du compte", + "password": "Changer le mot de passe", + "appearance": "Apparence", + "routeConfig": "Sécurité", + "installConfig": "Installation", + "smartRouting": "Routage intelligent" + }, + "market": { + "title": "Marché Hub - Marchés locaux et Cloud" + }, + "logs": { + "title": "Journaux système" + } + }, + "logs": { + "filters": "Filtres", + "search": "Rechercher dans les journaux...", + "autoScroll": "Défilement automatique", + "clearLogs": "Effacer les journaux", + "loading": "Chargement des journaux...", + "noLogs": "Aucun journal disponible.", + "noMatch": "Aucun journal ne correspond aux filtres actuels.", + "mainProcess": "Processus principal", + "childProcess": "Processus enfant", + "main": "Principal", + "child": "Enfant" + }, + "groups": { + "add": "Ajouter", + "addNew": "Ajouter un nouveau groupe", + "edit": "Modifier le groupe", + "delete": "Supprimer", + "confirmDelete": "Êtes-vous sûr de vouloir supprimer ce groupe ?", + "deleteWarning": "La suppression du groupe '{{name}}' le supprimera ainsi que toutes ses associations de serveurs. Cette action est irréversible.", + "name": "Nom du groupe", + "namePlaceholder": "Entrez le nom du groupe", + "nameRequired": "Le nom du groupe est requis", + "description": "Description", + "descriptionPlaceholder": "Entrez la description du groupe (facultatif)", + "createError": "Échec de la création du groupe", + "updateError": "Échec de la mise à jour du groupe", + "deleteError": "Échec de la suppression du groupe", + "serverAddError": "Échec de l'ajout du serveur au groupe", + "serverRemoveError": "Échec de la suppression du serveur du groupe", + "addServer": "Ajouter un serveur au groupe", + "selectServer": "Sélectionnez un serveur à ajouter", + "servers": "Serveurs dans le groupe", + "remove": "Retirer", + "noGroups": "Aucun groupe disponible. Créez un nouveau groupe pour commencer.", + "noServers": "Aucun serveur dans ce groupe.", + "noServerOptions": "Aucun serveur disponible", + "serverCount": "{{count}} serveurs", + "toolSelection": "Sélection d'outils", + "toolsSelected": "Sélectionné", + "allTools": "Tous", + "selectedTools": "Outils sélectionnés", + "selectAll": "Tout sélectionner", + "selectNone": "Ne rien sélectionner", + "configureTools": "Configurer les outils" + }, + "market": { + "title": "Installation locale", + "official": "Officiel", + "by": "Par", + "unknown": "Inconnu", + "tools": "outils", + "search": "Rechercher", + "searchPlaceholder": "Rechercher des serveurs par nom, catégorie ou tags", + "clearFilters": "Effacer", + "clearCategoryFilter": "", + "clearTagFilter": "", + "categories": "Catégories", + "tags": "Tags", + "showTags": "Afficher les tags", + "hideTags": "Masquer les tags", + "moreTags": "", + "noServers": "Aucun serveur trouvé correspondant à votre recherche", + "backToList": "Retour à la liste", + "install": "Installer", + "installing": "Installation en cours...", + "installed": "Installé", + "installServer": "Installer le serveur : {{name}}", + "installSuccess": "Serveur {{serverName}} installé avec succès", + "author": "Auteur", + "license": "Licence", + "repository": "Dépôt", + "examples": "Exemples", + "arguments": "Arguments", + "argumentName": "Nom", + "description": "Description", + "required": "Requis", + "example": "Exemple", + "viewSchema": "Voir le schéma", + "fetchError": "Erreur lors de la récupération des serveurs du marché", + "serverNotFound": "Serveur non trouvé", + "searchError": "Erreur lors de la recherche de serveurs", + "filterError": "Erreur lors du filtrage des serveurs par catégorie", + "tagFilterError": "Erreur lors du filtrage des serveurs par tag", + "noInstallationMethod": "Aucune méthode d'installation disponible pour ce serveur", + "showing": "Affichage de {{from}}-{{to}} sur {{total}} serveurs", + "perPage": "Par page", + "confirmVariablesMessage": "Veuillez vous assurer que ces variables sont correctement définies dans votre environnement d'exécution. Continuer l'installation du serveur ?", + "confirmAndInstall": "Confirmer et installer" + }, + "cloud": { + "title": "Support Cloud", + "subtitle": "Propulsé par MCPRouter", + "by": "Par", + "server": "Serveur", + "config": "Config", + "created": "Créé", + "updated": "Mis à jour", + "available": "Disponible", + "description": "Description", + "details": "Détails", + "tools": "Outils", + "tool": "outil", + "toolsAvailable": "{{count}} outil disponible||{{count}} outils disponibles", + "loadingTools": "Chargement des outils...", + "noTools": "Aucun outil disponible pour ce serveur", + "noDescription": "Aucune description disponible", + "viewDetails": "Voir les détails", + "parameters": "Paramètres", + "result": "Résultat", + "error": "Erreur", + "callTool": "Appeler", + "calling": "Appel en cours...", + "toolCallSuccess": "L'outil {{toolName}} a été exécuté avec succès", + "toolCallError": "Échec de l'appel de l'outil {{toolName}} : {{error}}", + "viewSchema": "Voir le schéma", + "backToList": "Retour au marché Cloud", + "search": "Rechercher", + "searchPlaceholder": "Rechercher des serveurs cloud par nom, titre ou auteur", + "clearFilters": "Effacer les filtres", + "clearCategoryFilter": "Effacer", + "clearTagFilter": "Effacer", + "categories": "Catégories", + "tags": "Tags", + "noCategories": "Aucune catégorie trouvée", + "noTags": "Aucun tag trouvé", + "noServers": "Aucun serveur cloud trouvé", + "fetchError": "Erreur lors de la récupération des serveurs cloud", + "serverNotFound": "Serveur cloud non trouvé", + "searchError": "Erreur lors de la recherche de serveurs cloud", + "filterError": "Erreur lors du filtrage des serveurs cloud par catégorie", + "tagFilterError": "Erreur lors du filtrage des serveurs cloud par tag", + "showing": "Affichage de {{from}}-{{to}} sur {{total}} serveurs cloud", + "perPage": "Par page", + "apiKeyNotConfigured": "Clé API MCPRouter non configurée", + "apiKeyNotConfiguredDescription": "Pour utiliser les serveurs cloud, vous devez configurer votre clé API MCPRouter.", + "getApiKey": "Obtenir une clé API", + "configureInSettings": "Configurer dans les paramètres", + "installServer": "Installer {{name}}", + "installSuccess": "Serveur {{name}} installé avec succès", + "installError": "Échec de l'installation du serveur : {{error}}" + }, + "tool": { + "run": "Exécuter", + "running": "Exécution en cours...", + "runTool": "Exécuter l'outil", + "cancel": "Annuler", + "noDescription": "Aucune description disponible", + "inputSchema": "Schéma d'entrée :", + "runToolWithName": "Exécuter l'outil : {{name}}", + "execution": "Exécution de l'outil", + "successful": "Réussi", + "failed": "Échoué", + "result": "Résultat :", + "error": "Erreur", + "errorDetails": "Détails de l'erreur :", + "noContent": "L'outil a été exécuté avec succès mais n'a renvoyé aucun contenu.", + "unknownError": "Une erreur inconnue est survenue", + "jsonResponse": "Réponse JSON :", + "toolResult": "Résultat de l'outil", + "noParameters": "Cet outil ne nécessite aucun paramètre.", + "selectOption": "Sélectionnez une option", + "enterValue": "Entrez la valeur {{type}}", + "enabled": "Activé", + "enableSuccess": "Outil {{name}} activé avec succès", + "disableSuccess": "Outil {{name}} désactivé avec succès", + "toggleFailed": "Échec du basculement de l'état de l'outil", + "parameters": "Paramètres de l'outil", + "formMode": "Mode formulaire", + "jsonMode": "Mode JSON", + "jsonConfiguration": "Configuration JSON", + "invalidJsonFormat": "Format JSON invalide", + "fixJsonBeforeSwitching": "Veuillez corriger le format JSON avant de passer en mode formulaire", + "item": "Élément {{index}}", + "addItem": "Ajouter un élément {{key}}", + "enterKey": "Entrez {{key}}" + }, + "prompt": { + "run": "Obtenir", + "running": "Obtention en cours...", + "result": "Résultat de l'invite", + "error": "Erreur de l'invite", + "execution": "Exécution de l'invite", + "successful": "Réussi", + "failed": "Échoué", + "errorDetails": "Détails de l'erreur :", + "noContent": "L'invite a été exécutée avec succès mais n'a renvoyé aucun contenu.", + "unknownError": "Une erreur inconnue est survenue", + "jsonResponse": "Réponse JSON :", + "description": "Description", + "messages": "Messages", + "noDescription": "Aucune description disponible", + "runPromptWithName": "Obtenir l'invite : {{name}}" + }, + "settings": { + "enableGlobalRoute": "Activer la route globale", + "enableGlobalRouteDescription": "Autoriser les connexions au point de terminaison /sse sans spécifier d'ID de groupe", + "enableGroupNameRoute": "Activer la route par nom de groupe", + "enableGroupNameRouteDescription": "Autoriser les connexions au point de terminaison /sse en utilisant les noms de groupe au lieu des ID de groupe", + "enableBearerAuth": "Activer l'authentification Bearer", + "enableBearerAuthDescription": "Exiger une authentification par jeton Bearer pour les requêtes MCP", + "bearerAuthKey": "Clé d'authentification Bearer", + "bearerAuthKeyDescription": "La clé d'authentification qui sera requise dans le jeton Bearer", + "bearerAuthKeyPlaceholder": "Entrez la clé d'authentification Bearer", + "skipAuth": "Ignorer l'authentification", + "skipAuthDescription": "Contourner l'exigence de connexion pour l'accès au frontend et à l'API (DÉSACTIVÉ PAR DÉFAUT pour des raisons de sécurité)", + "pythonIndexUrl": "URL du dépôt de paquets Python", + "pythonIndexUrlDescription": "Définir la variable d'environnement UV_DEFAULT_INDEX pour l'installation de paquets Python", + "pythonIndexUrlPlaceholder": "ex. https://pypi.org/simple", + "npmRegistry": "URL du registre NPM", + "npmRegistryDescription": "Définir la variable d'environnement npm_config_registry pour l'installation de paquets NPM", + "npmRegistryPlaceholder": "ex. https://registry.npmjs.org/", + "baseUrl": "URL de base", + "baseUrlDescription": "URL de base pour les requêtes MCP", + "baseUrlPlaceholder": "ex. http://localhost:3000", + "installConfig": "Installation", + "systemConfigUpdated": "Configuration système mise à jour avec succès", + "enableSmartRouting": "Activer le routage intelligent", + "enableSmartRoutingDescription": "Activer la fonctionnalité de routage intelligent pour rechercher l'outil le plus approprié en fonction de l'entrée (en utilisant le nom de groupe $smart)", + "dbUrl": "URL PostgreSQL (nécessite le support de pgvector)", + "dbUrlPlaceholder": "ex. postgresql://user:password@localhost:5432/dbname", + "openaiApiBaseUrl": "URL de base de l'API OpenAI", + "openaiApiBaseUrlPlaceholder": "https://api.openai.com/v1", + "openaiApiKey": "Clé API OpenAI", + "openaiApiKeyPlaceholder": "Entrez la clé API OpenAI", + "openaiApiEmbeddingModel": "Modèle d'intégration OpenAI", + "openaiApiEmbeddingModelPlaceholder": "text-embedding-3-small", + "smartRoutingConfigUpdated": "Configuration du routage intelligent mise à jour avec succès", + "smartRoutingRequiredFields": "L'URL de la base de données et la clé API OpenAI sont requises pour activer le routage intelligent", + "smartRoutingValidationError": "Veuillez remplir les champs obligatoires avant d'activer le routage intelligent : {{fields}}", + "mcpRouterConfig": "Marché Cloud", + "mcpRouterApiKey": "Clé API MCPRouter", + "mcpRouterApiKeyDescription": "Clé API pour accéder aux services du marché cloud MCPRouter", + "mcpRouterApiKeyPlaceholder": "Entrez la clé API MCPRouter", + "mcpRouterReferer": "Référent", + "mcpRouterRefererDescription": "En-tête Referer pour les requêtes API MCPRouter", + "mcpRouterRefererPlaceholder": "https://www.mcphubx.com", + "mcpRouterTitle": "Titre", + "mcpRouterTitleDescription": "En-tête Title pour les requêtes API MCPRouter", + "mcpRouterTitlePlaceholder": "MCPHub", + "mcpRouterBaseUrl": "URL de base", + "mcpRouterBaseUrlDescription": "URL de base pour l'API MCPRouter", + "mcpRouterBaseUrlPlaceholder": "https://api.mcprouter.to/v1" + }, + "dxt": { + "upload": "Télécharger", + "uploadTitle": "Télécharger l'extension DXT", + "dropFileHere": "Déposez votre fichier .dxt ici", + "orClickToSelect": "ou cliquez pour sélectionner depuis votre ordinateur", + "invalidFileType": "Veuillez sélectionner un fichier .dxt valide", + "noFileSelected": "Veuillez sélectionner un fichier .dxt à télécharger", + "uploading": "Téléchargement en cours...", + "uploadFailed": "Échec du téléchargement du fichier DXT", + "installServer": "Installer le serveur MCP depuis DXT", + "extensionInfo": "Informations sur l'extension", + "name": "Nom", + "version": "Version", + "description": "Description", + "author": "Auteur", + "tools": "Outils", + "serverName": "Nom du serveur", + "serverNamePlaceholder": "Entrez un nom pour ce serveur", + "install": "Installer", + "installing": "Installation en cours...", + "installFailed": "Échec de l'installation du serveur depuis DXT", + "serverExistsTitle": "Le serveur existe déjà", + "serverExistsConfirm": "Le serveur '{{serverName}}' existe déjà. Voulez-vous le remplacer par la nouvelle version ?", + "override": "Remplacer" + }, + "users": { + "add": "Ajouter un utilisateur", + "addNew": "Ajouter un nouvel utilisateur", + "edit": "Modifier l'utilisateur", + "delete": "Supprimer l'utilisateur", + "create": "Créer un utilisateur", + "update": "Mettre à jour l'utilisateur", + "username": "Nom d'utilisateur", + "password": "Mot de passe", + "newPassword": "Nouveau mot de passe", + "confirmPassword": "Confirmer le mot de passe", + "adminRole": "Administrateur", + "admin": "Admin", + "user": "Utilisateur", + "permissions": "Permissions", + "adminPermissions": "Accès complet au système", + "userPermissions": "Accès limité", + "currentUser": "Vous", + "noUsers": "Aucun utilisateur trouvé", + "adminRequired": "Un accès administrateur est requis pour gérer les utilisateurs", + "usernameRequired": "Le nom d'utilisateur est requis", + "passwordRequired": "Le mot de passe est requis", + "passwordTooShort": "Le mot de passe doit comporter au moins 6 caractères", + "passwordMismatch": "Les mots de passe ne correspondent pas", + "usernamePlaceholder": "Entrez le nom d'utilisateur", + "passwordPlaceholder": "Entrez le mot de passe", + "newPasswordPlaceholder": "Laissez vide pour conserver le mot de passe actuel", + "confirmPasswordPlaceholder": "Confirmez le nouveau mot de passe", + "createError": "Échec de la création de l'utilisateur", + "updateError": "Échec de la mise à jour de l'utilisateur", + "deleteError": "Échec de la suppression de l'utilisateur", + "statsError": "Échec de la récupération des statistiques utilisateur", + "deleteConfirmation": "Êtes-vous sûr de vouloir supprimer l'utilisateur '{{username}}' ? Cette action est irréversible.", + "confirmDelete": "Supprimer l'utilisateur", + "deleteWarning": "Êtes-vous sûr de vouloir supprimer l'utilisateur '{{username}}' ? Cette action est irréversible." + }, + "api": { + "errors": { + "readonly": "Lecture seule pour l'environnement de démonstration", + "invalid_credentials": "Nom d'utilisateur ou mot de passe invalide", + "serverNameRequired": "Le nom du serveur est requis", + "serverConfigRequired": "La configuration du serveur est requise", + "serverConfigInvalid": "La configuration du serveur doit inclure une URL, une URL de spécification OpenAPI ou un schéma, ou une commande avec des arguments", + "serverTypeInvalid": "Le type de serveur doit être l'un des suivants : stdio, sse, streamable-http, openapi", + "urlRequiredForType": "L'URL est requise pour le type de serveur {{type}}", + "openapiSpecRequired": "L'URL de la spécification OpenAPI ou le schéma est requis pour le type de serveur openapi", + "headersInvalidFormat": "Les en-têtes doivent être un objet", + "headersNotSupportedForStdio": "Les en-têtes ne sont pas pris en charge pour le type de serveur stdio", + "serverNotFound": "Serveur non trouvé", + "failedToRemoveServer": "Serveur non trouvé ou échec de la suppression", + "internalServerError": "Erreur interne du serveur", + "failedToGetServers": "Échec de la récupération des informations sur les serveurs", + "failedToGetServerSettings": "Échec de la récupération des paramètres du serveur", + "failedToGetServerConfig": "Échec de la récupération de la configuration du serveur", + "failedToSaveSettings": "Échec de l'enregistrement des paramètres", + "toolNameRequired": "Le nom du serveur et le nom de l'outil sont requis", + "descriptionMustBeString": "La description doit être une chaîne de caractères", + "groupIdRequired": "L'ID de groupe est requis", + "groupNameRequired": "Le nom du groupe est requis", + "groupNotFound": "Groupe non trouvé", + "groupIdAndServerNameRequired": "L'ID de groupe和le nom du serveur sont requis", + "groupOrServerNotFound": "Groupe ou serveur non trouvé", + "toolsMustBeAllOrArray": "Les outils doivent être \"all\" ou un tableau de chaînes de caractères", + "serverNameAndToolNameRequired": "Le nom du serveur et le nom de l'outil sont requis", + "usernameRequired": "Le nom d'utilisateur est requis", + "userNotFound": "Utilisateur non trouvé", + "failedToGetUsers": "Échec de la récupération des informations sur les utilisateurs", + "failedToGetUserInfo": "Échec de la récupération des informations sur l'utilisateur", + "failedToGetUserStats": "Échec de la récupération des statistiques de l'utilisateur", + "marketServerNameRequired": "Le nom du serveur du marché est requis", + "marketServerNotFound": "Serveur du marché non trouvé", + "failedToGetMarketServers": "Échec de la récupération des informations sur les serveurs du marché", + "failedToGetMarketServer": "Échec de la récupération des informations sur le serveur du marché", + "failedToGetMarketCategories": "Échec de la récupération des catégories du marché", + "failedToGetMarketTags": "Échec de la récupération des tags du marché", + "failedToSearchMarketServers": "Échec de la recherche des serveurs du marché", + "failedToFilterMarketServers": "Échec du filtrage des serveurs du marché", + "failedToProcessDxtFile": "Échec du traitement du fichier DXT" + }, + "success": { + "serverCreated": "Serveur créé avec succès", + "serverUpdated": "Serveur mis à jour avec succès", + "serverRemoved": "Serveur supprimé avec succès", + "serverToggled": "État du serveur basculé avec succès", + "toolToggled": "Outil {{name}} {{action}} avec succès", + "toolDescriptionUpdated": "Description de l'outil {{name}} mise à jour avec succès", + "systemConfigUpdated": "Configuration système mise à jour avec succès", + "groupCreated": "Groupe créé avec succès", + "groupUpdated": "Groupe mis à jour avec succès", + "groupDeleted": "Groupe supprimé avec succès", + "serverAddedToGroup": "Serveur ajouté au groupe avec succès", + "serverRemovedFromGroup": "Serveur supprimé du groupe avec succès", + "serverToolsUpdated": "Outils du serveur mis à jour avec succès" + } + } +} diff --git a/locales/zh.json b/locales/zh.json index b1f8633..4fb1f47 100644 --- a/locales/zh.json +++ b/locales/zh.json @@ -93,6 +93,10 @@ "updateError": "更新服务器失败", "editTitle": "编辑服务器: {{serverName}}", "type": "服务器类型", + "typeStdio": "STDIO", + "typeSse": "SSE", + "typeStreamableHttp": "流式 HTTP", + "typeOpenapi": "OpenAPI", "command": "命令", "arguments": "参数", "envVars": "环境变量", @@ -145,11 +149,17 @@ "httpAuthConfig": "HTTP 认证配置", "httpScheme": "认证方案", "httpCredentials": "凭据", + "httpSchemeBasic": "Basic", + "httpSchemeBearer": "Bearer", + "httpSchemeDigest": "Digest", "oauth2Config": "OAuth 2.0 配置", "oauth2Token": "访问令牌", "openIdConnectConfig": "OpenID Connect 配置", "openIdConnectUrl": "发现 URL", - "openIdConnectToken": "ID 令牌" + "openIdConnectToken": "ID 令牌", + "apiKeyInHeader": "请求头", + "apiKeyInQuery": "查询", + "apiKeyInCookie": "Cookie" } }, "status": { @@ -191,7 +201,13 @@ "copyFailed": "复制失败", "close": "关闭", "confirm": "确认", - "language": "语言" + "language": "语言", + "true": "是", + "false": "否", + "dismiss": "忽略", + "github": "GitHub", + "wechat": "微信", + "discord": "Discord" }, "nav": { "dashboard": "仪表盘",