Compare commits

...

7 Commits

Author SHA1 Message Date
comeback01
9a65532a50 feat: add french localization (#337)
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2025-09-12 14:27:05 +08:00
dependabot[bot]
c5aa97de50 chore(deps-dev): bump vite from 6.3.5 to 6.3.6 (#334)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-10 12:42:00 +08:00
dependabot[bot]
271c9fe2c3 chore(deps-dev): bump i18next from 24.2.3 to 25.4.2 (#329)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-05 08:51:54 +08:00
dependabot[bot]
d59961c4d4 chore(deps-dev): bump next from 15.5.0 to 15.5.2 (#328)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-05 08:51:23 +08:00
dependabot[bot]
d0ec80303a chore(deps-dev): bump jest-mock-extended from 4.0.0-beta1 to 4.0.0 (#330)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-04 22:49:30 +08:00
dependabot[bot]
69e92b5aa8 chore(deps): bump @apidevtools/swagger-parser from 11.0.1 to 12.0.0 (#331)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-04 22:48:29 +08:00
dependabot[bot]
5acae64b29 chore(deps-dev): bump @typescript-eslint/eslint-plugin from 6.21.0 to 7.0.0 (#327)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-04 22:47:30 +08:00
14 changed files with 951 additions and 261 deletions

View File

@@ -231,8 +231,8 @@ const CloudServerDetail: React.FC<CloudServerDetailProps> = ({
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"
>
<option value=""></option>
<option value="true">True</option>
<option value="false">False</option>
<option value="true">{t('common.true')}</option>
<option value="false">{t('common.false')}</option>
</select>
);
} else if (propSchema.type === 'number' || propSchema.type === 'integer') {

View File

@@ -306,7 +306,7 @@ const ServerForm = ({ onSubmit, onCancel, initialData = null, modalTitle, formEr
onChange={() => updateServerType('stdio')}
className="mr-1"
/>
<label htmlFor="command">STDIO</label>
<label htmlFor="command">{t('server.typeStdio')}</label>
</div>
<div>
<input
@@ -318,7 +318,7 @@ const ServerForm = ({ onSubmit, onCancel, initialData = null, modalTitle, formEr
onChange={() => updateServerType('sse')}
className="mr-1"
/>
<label htmlFor="url">SSE</label>
<label htmlFor="url">{t('server.typeSse')}</label>
</div>
<div>
<input
@@ -330,7 +330,7 @@ const ServerForm = ({ onSubmit, onCancel, initialData = null, modalTitle, formEr
onChange={() => updateServerType('streamable-http')}
className="mr-1"
/>
<label htmlFor="streamable-http">Streamable HTTP</label>
<label htmlFor="streamable-http">{t('server.typeStreamableHttp')}</label>
</div>
<div>
<input
@@ -342,7 +342,7 @@ const ServerForm = ({ onSubmit, onCancel, initialData = null, modalTitle, formEr
onChange={() => updateServerType('openapi')}
className="mr-1"
/>
<label htmlFor="openapi">OpenAPI</label>
<label htmlFor="openapi">{t('server.typeOpenapi')}</label>
</div>
</div>
</div>
@@ -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"
>
<option value="header">Header</option>
<option value="query">Query</option>
<option value="cookie">Cookie</option>
<option value="header">{t('server.openapi.apiKeyInHeader')}</option>
<option value="query">{t('server.openapi.apiKeyInQuery')}</option>
<option value="cookie">{t('server.openapi.apiKeyInCookie')}</option>
</select>
</div>
<div>
@@ -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"
>
<option value="basic">Basic</option>
<option value="bearer">Bearer</option>
<option value="digest">Digest</option>
<option value="basic">{t('server.openapi.httpSchemeBasic')}</option>
<option value="bearer">{t('server.openapi.httpSchemeBearer')}</option>
<option value="digest">{t('server.openapi.httpSchemeDigest')}</option>
</select>
</div>
<div>

View File

@@ -1,6 +1,8 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
export const DiscordIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => {
const { t } = useTranslation();
return (
<svg
role="img"
@@ -11,7 +13,7 @@ export const DiscordIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => {
fill="currentColor"
{...props}
>
<title>Discord</title>
<title>{t('common.discord')}</title>
<path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z" />
</svg>
);

View File

@@ -1,6 +1,8 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
export const GitHubIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => {
const { t } = useTranslation();
return (
<svg
role="img"
@@ -11,7 +13,7 @@ export const GitHubIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => {
fill="currentColor"
{...props}
>
<title>GitHub</title>
<title>{t('common.github')}</title>
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
</svg>
);

View File

@@ -1,6 +1,8 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
export const SponsorIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => {
const { t } = useTranslation();
return (
<svg
role="img"
@@ -11,7 +13,7 @@ export const SponsorIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => {
fill="currentColor"
{...props}
>
<title>Sponsor</title>
<title>{t('sponsor.label')}</title>
<path d="M17.625 1.499c-2.32 0-4.354 1.203-5.625 3.03-1.271-1.827-3.305-3.03-5.625-3.03C3.129 1.499 0 4.253 0 8.249c0 4.275 3.068 7.847 5.828 10.227a33.14 33.14 0 0 0 5.616 3.876l.028.017.008.003-.001.003c.163.085.342.126.521.125.179.001.358-.041.521-.125l-.001-.003.008-.003.028-.017a33.14 33.14 0 0 0 5.616-3.876C20.932 16.096 24 12.524 24 8.249c0-3.996-3.129-6.75-6.375-6.75zm-.919 15.275a30.766 30.766 0 0 1-4.703 3.316l-.004-.002-.004.002a30.955 30.955 0 0 1-4.703-3.316c-2.677-2.307-5.047-5.298-5.047-8.523 0-2.754 2.121-4.5 4.125-4.5 2.06 0 3.914 1.479 4.544 3.684.143.495.596.797 1.086.796.49.001.943-.302 1.085-.796.63-2.205 2.484-3.684 4.544-3.684 2.004 0 4.125 1.746 4.125 4.5 0 3.225-2.37 6.216-5.048 8.523z" />
</svg>
);

View File

@@ -1,6 +1,8 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
export const WeChatIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => {
const { t } = useTranslation();
return (
<svg
role="img"
@@ -11,7 +13,7 @@ export const WeChatIcon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => {
fill="currentColor"
{...props}
>
<title>WeChat</title>
<title>{t('common.wechat')}</title>
<path d="M8.691 2.188C3.891 2.188 0 5.476 0 9.53c0 2.212 1.17 4.203 3.002 5.55a.59.59 0 0 1 .213.665l-.39 1.48c-.019.07-.048.141-.048.213 0 .163.13.295.29.295a.326.326 0 0 0 .167-.054l1.903-1.114a.864.864 0 0 1 .717-.098 10.16 10.16 0 0 0 2.837.403c.276 0 .543-.027.811-.05-.857-2.578.157-4.972 1.932-6.446 1.703-1.415 3.882-1.98 5.853-1.838-.576-3.583-4.196-6.348-8.596-6.348zM5.785 5.991c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 0 1-1.162 1.178A1.17 1.17 0 0 1 4.623 7.17c0-.651.52-1.18 1.162-1.18zm5.813 0c.642 0 1.162.529 1.162 1.18a1.17 1.17 0 0 1-1.162 1.178 1.17 1.17 0 0 1-1.162-1.178c0-.651.52-1.18 1.162-1.18zm5.34 2.867c-1.797-.052-3.746.512-5.28 1.786-1.72 1.428-2.687 3.72-1.78 6.22.942 2.453 3.666 4.229 6.884 4.229.826 0 1.622-.12 2.361-.336a.722.722 0 0 1 .598.082l1.584.926a.272.272 0 0 0 .14.047c.134 0 .24-.111.24-.247 0-.06-.023-.12-.038-.177l-.327-1.233a.582.582 0 0 1-.023-.156.49.49 0 0 1 .201-.398C23.024 18.48 24 16.82 24 14.98c0-3.21-2.931-5.837-6.656-6.088V8.89c-.135-.01-.27-.027-.407-.03zm-2.53 3.274c.535 0 .969.44.969.982a.976.976 0 0 1-.969.983.976.976 0 0 1-.969-.983c0-.542.434-.982.97-.982zm4.844 0c.535 0 .969.44.969.982a.976.976 0 0 1-.969.983.976.976 0 0 1-.969-.983c0-.542.434-.982.969-.982z" />
</svg>
);

View File

@@ -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

View File

@@ -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<ToastProps> = ({
onClose,
visible
}) => {
const { t } = useTranslation();
useEffect(() => {
if (visible) {
const timer = setTimeout(() => {
@@ -83,7 +86,7 @@ const Toast: React.FC<ToastProps> = ({
`hover:bg-${type}-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-${type}-500`
)}
>
<span className="sr-only">Dismiss</span>
<span className="sr-only">{t('common.dismiss')}</span>
<X className="h-5 w-5" />
</button>
</div>

View File

@@ -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',

View File

@@ -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",

621
locales/fr.json Normal file
View File

@@ -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"
}
}
}

View File

@@ -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": "仪表盘",

View File

@@ -45,7 +45,7 @@
"author": "",
"license": "ISC",
"dependencies": {
"@apidevtools/swagger-parser": "^11.0.1",
"@apidevtools/swagger-parser": "^12.0.0",
"@modelcontextprotocol/sdk": "^1.17.4",
"@types/adm-zip": "^0.5.7",
"@types/bcrypt": "^6.0.0",
@@ -91,7 +91,7 @@
"@types/react-dom": "^19.1.7",
"@types/supertest": "^6.0.3",
"@types/uuid": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/eslint-plugin": "^7.0.0",
"@typescript-eslint/parser": "^6.21.0",
"@vitejs/plugin-react": "^4.7.0",
"autoprefixer": "^10.4.21",
@@ -99,11 +99,11 @@
"clsx": "^2.1.1",
"concurrently": "^9.2.0",
"eslint": "^8.57.1",
"i18next": "^24.2.3",
"i18next": "^25.5.0",
"i18next-browser-languagedetector": "^8.2.0",
"jest": "^29.7.0",
"jest-environment-node": "^30.0.5",
"jest-mock-extended": "4.0.0-beta1",
"jest-mock-extended": "4.0.0",
"lucide-react": "^0.486.0",
"next": "^15.5.0",
"postcss": "^8.5.6",

491
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff