diff --git a/README.es-ES.md b/README.es-ES.md
index 9b6627ed6..34d6ea880 100644
--- a/README.es-ES.md
+++ b/README.es-ES.md
@@ -1,10 +1,10 @@
# ReactFlux
-Lea este texto en otros idiomas: [English](README.md), [简体中文](README.zh-CN.md)
+Lea este texto en otros idiomas: [English](README.md), [Français](README.fr-FR.md), [简体中文](README.zh-CN.md)
## Descripción general
-ReactFlux es una interfaz web de terceros para [Miniflux](https://github.com/miniflux/miniflux), cuyo objetivo es proporcionar una experiencia de lectura más fácil de usar.
+ReactFlux es una interfaz web de terceros para [Miniflux](https://github.com/miniflux/v2), cuyo objetivo es proporcionar una experiencia de lectura más fácil de usar.
Las funcionalidades clave incluyen:
@@ -26,8 +26,8 @@ Las funcionalidades clave incluyen:
## Capturas de pantalla
-![Interfaz](images/light.png)
-![Ajustes](images/dark.png)
+![Modo Claro](images/light.png)
+![Modo Oscuro](images/dark.png)
## Demo
diff --git a/README.fr-FR.md b/README.fr-FR.md
new file mode 100644
index 000000000..f8650e51d
--- /dev/null
+++ b/README.fr-FR.md
@@ -0,0 +1,102 @@
+# ReactFlux
+
+Lire dans d'autres langues : [English](README.md), [Español](README.es-ES.md), [简体中文](README.zh-CN.md)
+
+## Aperçu
+
+ReactFlux est une interface web tierce pour [Miniflux](https://github.com/miniflux/v2), visant à offrir une expérience de lecture plus conviviale.
+
+Les fonctionnalités principales incluent :
+
+- Design d'interface moderne
+- Mise en page responsive
+- Prise en charge du mode sombre et des thèmes personnalisés
+- Recherche d'articles et de flux avec une syntaxe similaire à Google
+- Filtrage des articles par date de publication
+- Gestion des flux et des groupes
+- Raccourcis clavier (personnalisables)
+- Marquage automatique des articles comme lus lors du défilement
+- Mise à jour par lot de l'hôte des URLs de souscription filtrées (utile pour remplacer les instances RSSHub)
+- Actualisation par lot des souscriptions récemment en erreur
+- Dédoublonnage des articles par hash, titre ou URL lors du chargement de la liste
+- Support multilingue (inclut : Anglais / Español / 简体中文)
+- Sauvegarde d'articles vers des services tiers
+- Coloration syntaxique pour les blocs de code
+- D'autres fonctionnalités à découvrir...
+
+## Captures d'écran
+
+![Mode Clair](images/light.png)
+![Mode Sombre](images/dark.png)
+
+## Démo
+
+[Instance de démonstration en ligne](https://reactflux.pages.dev/login)
+
+## Déploiement
+
+### Cloudflare Pages
+
+ReactFlux est construit avec React et génère un ensemble de fichiers web statiques après la compilation, qui peuvent être directement déployés sur Cloudflare Pages.
+
+Vous pouvez également le déployer vous-même sur Cloudflare Pages en sélectionnant `Framework preset` comme `Create React App`.
+
+### Vercel
+
+[![Déployer sur Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/electh/ReactFlux)
+
+### Zeabur
+
+[![Déployer sur Zeabur](https://zeabur.com/button.svg)](https://zeabur.com/templates/OKXO3W)
+
+### Docker
+
+```bash
+docker run -p 2000:2000 electh/reactflux
+```
+
+## Configuration
+
+Vous avez besoin d'une instance Miniflux fonctionnelle pour utiliser ce projet, qui prend en charge les deux méthodes de connexion suivantes :
+
+1. Se connecter en utilisant le nom d'utilisateur et le mot de passe de l'instance (non recommandé) ;
+2. Se connecter en utilisant un jeton Miniflux, qui peut être généré dans "Paramètres > Clés API > Créer une nouvelle clé API".
+
+## Branches
+
+- Branche `main` : Fournit les fonctionnalités les plus complètes. Les nouvelles fonctionnalités sont généralement publiées d'abord sur cette branche, adaptée à la plupart des utilisateurs.
+- Branche `next` : Initialement créée pour améliorer la compatibilité avec les appareils mobiles, offrant une meilleure expérience et performance pour les appareils mobiles tout en restant compatible avec les ordinateurs de bureau. Cette branche manque actuellement de fonctionnalités comme les raccourcis clavier et migrera sélectivement les fonctionnalités de la branche `main`.
+- Branche `gh-pages` : Utilisée pour compiler et déployer la branche `main` sur GitHub Pages.
+
+Si vous souhaitez rapidement essayer la branche `next`, voici une [instance en ligne](https://arcoflux.pages.dev/login).
+
+## Contributeurs
+
+> Merci à tous les contributeurs qui ont rendu ce projet possible !
+
+
+
+
+
+
+
+
+ NekoAria
+
+ Contributeur Principal
+ |
+
+
+
+
+
+ electh
+
+ Initiateur du Projet
+ |
+
+
+
+## Historique des étoiles
+
+[![Historique des étoiles](https://starchart.cc/electh/ReactFlux.svg)](https://starchart.cc/electh/ReactFlux)
diff --git a/README.md b/README.md
index b90e11067..1fb2b4fc2 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,10 @@
# ReactFlux
-Read in other languages: [Español](README.es-ES.md), [简体中文](README.zh-CN.md)
+Read in other languages: [Español](README.es-ES.md), [Français](README.fr-FR.md), [简体中文](README.zh-CN.md)
## Overview
-ReactFlux is a third-party web frontend for [Miniflux](https://github.com/miniflux/miniflux), aimed at providing a more user-friendly reading experience.
+ReactFlux is a third-party web frontend for [Miniflux](https://github.com/miniflux/v2), aimed at providing a more user-friendly reading experience.
Key features include:
diff --git a/README.zh-CN.md b/README.zh-CN.md
index bd3fb9373..0da3e426d 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -1,10 +1,10 @@
# ReactFlux
-阅读其他语言版本: [English](README.md), [Español](README.es-ES.md)
+阅读其他语言版本: [English](README.md), [Español](README.es-ES.md), [Français](README.fr-FR.md)
## 概述
-Reactflux 是 [Miniflux](https://github.com/miniflux/miniflux) 的第三方 Web 前端,旨在提供更加友好的阅读体验。
+Reactflux 是 [Miniflux](https://github.com/miniflux/v2) 的第三方 Web 前端,旨在提供更加友好的阅读体验。
主要特性包括:
@@ -26,8 +26,8 @@ Reactflux 是 [Miniflux](https://github.com/miniflux/miniflux) 的第三方 Web
## 截图
-![Light Mode](images/light.png)
-![Dark Mode](images/dark.png)
+![浅色模式](images/light.png)
+![深色模式](images/dark.png)
## 演示
diff --git a/src/components/Settings/General.jsx b/src/components/Settings/General.jsx
index b7cbc024b..779daa748 100644
--- a/src/components/Settings/General.jsx
+++ b/src/components/Settings/General.jsx
@@ -7,6 +7,7 @@ import SettingItem from "./SettingItem";
const languageOptions = [
{ label: "English", value: "en-US" },
{ label: "Español", value: "es-ES" },
+ { label: "Français", value: "fr-FR" },
{ label: "简体中文", value: "zh-CN" },
];
diff --git a/src/hooks/useLanguage.js b/src/hooks/useLanguage.js
index bcf46fd94..e6759cf0c 100644
--- a/src/hooks/useLanguage.js
+++ b/src/hooks/useLanguage.js
@@ -2,6 +2,7 @@ import { useStore } from "@nanostores/react";
import dayjs from "dayjs";
import "dayjs/locale/en";
import "dayjs/locale/es";
+import "dayjs/locale/fr";
import "dayjs/locale/zh-cn";
import { map } from "nanostores";
import Polyglot from "node-polyglot";
@@ -10,6 +11,12 @@ import { settingsState, updateSettings } from "../store/settingsState";
import { getBrowserLanguage } from "../utils/locales";
import { createSetter } from "../utils/nanostores";
+const languageToLocale = {
+ "zh-CN": "zh-cn",
+ es: "es",
+ fr: "fr",
+};
+
export const polyglotState = map({
polyglot: null,
});
@@ -49,13 +56,11 @@ const useLanguage = () => {
} else {
loadLanguage(language);
- if (language === "zh-CN") {
- dayjs.locale("zh-cn");
- } else if (language === "es" || language.startsWith("es-")) {
- dayjs.locale("es");
- } else {
- dayjs.locale("en");
- }
+ const locale =
+ language.startsWith("es-") || language.startsWith("fr-")
+ ? language.substring(0, 2)
+ : languageToLocale[language] || "en";
+ dayjs.locale(locale);
}
}, [language]);
};
diff --git a/src/locales/fr-FR.json b/src/locales/fr-FR.json
new file mode 100644
index 000000000..d57f91ffa
--- /dev/null
+++ b/src/locales/fr-FR.json
@@ -0,0 +1,258 @@
+{
+ "login": {
+ "success": "Connexion réussie",
+ "auth_error": "Veuillez vérifier votre adresse de serveur et vos informations d'identification",
+ "login_to_your_server": "Connectez-vous à votre serveur",
+ "submit_error": "Veuillez remplir tous les champs obligatoires",
+ "server_label": "Adresse du serveur",
+ "server_placeholder": "Veuillez saisir l'adresse du serveur",
+ "token_label": "Jeton API",
+ "token_placeholder": "Veuillez saisir le jeton API",
+ "username_label": "Nom d'utilisateur",
+ "username_placeholder": "Veuillez saisir votre nom d'utilisateur",
+ "password_label": "Mot de passe",
+ "password_placeholder": "Veuillez saisir votre mot de passe",
+ "login_button": "Se connecter",
+ "another_login_method": "Ou se connecter avec",
+ "another_login_button": "Nom d'utilisateur et mot de passe",
+ "need_help": "Besoin d'aide ?",
+ "miniflux_official_website": "Aller sur le site officiel de Miniflux"
+ },
+ "sidebar": {
+ "all": "Tout",
+ "today": "Aujourd'hui",
+ "starred": "Favoris",
+ "history": "Historique",
+ "articles": "Articles",
+ "feeds": "Flux"
+ },
+ "actions": {
+ "copy_to_clipboard_tooltip": "Copier dans le presse-papiers",
+ "copied": "Copié !",
+ "mark_as_read_error": "Impossible de marquer comme lu, veuillez réessayer plus tard",
+ "mark_as_unread_error": "Impossible de marquer comme non lu, veuillez réessayer plus tard",
+ "star_error": "Impossible de marquer comme favori, veuillez réessayer plus tard",
+ "unstar_error": "Impossible de démarquer comme favori, veuillez réessayer plus tard",
+ "fetched_content_success": "Contenu récupéré avec succès",
+ "fetched_content_error": "Impossible de récupérer le contenu, veuillez réessayer plus tard",
+ "saved_to_third-party_services_success": "Sauvegardé avec succès dans les services tiers",
+ "saved_to_third-party_services_error": "Impossible de sauvegarder dans les services tiers, veuillez réessayer plus tard ou vérifier vos paramètres d'intégration"
+ },
+ "article_card": {
+ "reading_time": "%{time} de lecture",
+ "starred": "Marqué comme favori",
+ "unstarred": "Démarqué comme favori",
+ "marked_as_read": "Marqué comme lu",
+ "marked_as_unread": "Démarqué comme lu",
+ "update_failed": "Impossible de mettre à jour, veuillez réessayer",
+ "close_tooltip": "Fermer l'article",
+ "previous_tooltip": "Article précédent",
+ "next_tooltip": "Article suivant",
+ "mark_as_read_tooltip": "Marquer comme lu",
+ "mark_as_unread_tooltip": "Démarquer comme lu",
+ "star_tooltip": "Marquer comme favori",
+ "unstar_tooltip": "Démarquer comme favori",
+ "fetch_original_tooltip": "Récupérer le contenu original",
+ "save_to_third_party_services_tooltip": "Sauvegarder dans les services tiers"
+ },
+ "article_list": {
+ "sort_direction_desc": "Les plus récents en premier",
+ "sort_direction_asc": "Les plus anciens en premier",
+ "filter_status_all": "Tout",
+ "filter_status_unread": "Non lus",
+ "mark_all_as_read_success": "Tous les articles marqués comme lus",
+ "mark_all_as_read_error": "Impossible de marquer tous les articles comme lus",
+ "mark_all_as_read_confirm": "Marquer tous les articles comme lus ?",
+ "mark_all_as_read_tooltip": "Marquer tous les articles comme lus",
+ "refresh_tooltip": "Rafraîchir"
+ },
+ "content": {
+ "mark_as_read_error": "Impossible de marquer comme lu, veuillez réessayer plus tard"
+ },
+ "deduplicate": {
+ "mark_as_read_error": "Impossible de marquer les articles en double comme lus"
+ },
+ "search": {
+ "placeholder": "Rechercher...",
+ "clear_date": "Effacer",
+ "select_date": "Sélectionner une date",
+ "today": "Aujourd'hui",
+ "tooltip": "Syntaxe de recherche :\n• Texte : apple banana\n• Texte exact : \"red apple\"\n• Exclure : -text ou -\"text\"\n• Doit inclure : +text ou +\"text\"\n• Recherche OU : text1|text2\nExemple : \"red apple\" +fresh -rotten banana|orange",
+ "type_title": "Titre",
+ "type_content": "Contenu",
+ "type_author": "Auteur",
+ "type_feed_url": "URL du flux",
+ "type_site_url": "URL du site"
+ },
+ "main": {
+ "add_feed_success": "Flux ajouté avec succès",
+ "add_feed_error": "Impossible d'ajouter le flux",
+ "add_feed_error_duplicate": "Ce flux existe déjà",
+ "add_feed_url_empty": "L'URL du flux ne peut pas être vide",
+ "add_feed_modal_title": "Ajouter un flux",
+ "add_feed_modal_feed_url_label": "URL du flux",
+ "add_feed_modal_feed_url_placeholder": "Veuillez saisir l'URL du flux",
+ "add_feed_modal_category_label": "Catégorie",
+ "add_feed_modal_category_placeholder": "Veuillez sélectionner une catégorie",
+ "add_feed_modal_crawler_label": "Récupérer le contenu original"
+ },
+ "header": {
+ "theme": "Mode sombre",
+ "theme_option_light": "Clair",
+ "theme_option_dark": "Sombre",
+ "theme_option_system": "Système",
+ "logout_success": "Déconnexion réussie",
+ "add_feed": "Ajouter un flux",
+ "show_all_feeds": "Afficher tous les flux",
+ "hide_some_feeds": "Masquer certains flux",
+ "settings": "Paramètres",
+ "miniflux_settings": "Paramètres de Miniflux",
+ "reset_settings": "Réinitialiser les paramètres",
+ "logout": "Déconnexion",
+ "settings_reset_confirm": "Confirmer la réinitialisation",
+ "settings_reset_description": "Êtes-vous sûr de vouloir réinitialiser vos paramètres ? Cette action est irréversible.",
+ "logout_confirm": "Confirmer la déconnexion",
+ "logout_description": "Êtes-vous sûr de vouloir vous déconnecter ? Cette action est irréversible."
+ },
+ "feed_table": {
+ "refresh_success": "Rafraîchi",
+ "refresh_error": "Impossible de rafraîchir",
+ "refresh_feed": "Rafraîchir le flux",
+ "bulk_update_success": "Mise à jour en masse réussie",
+ "bulk_update_error": "Impossible de mettre à jour en masse, veuillez réessayer",
+ "bulk_refresh_error_feeds_message": "Début de la mise à jour des flux en erreur, veuillez patienter",
+ "bulk_refresh_error_feeds_result": "Flux mis à jour. Succès : %{success}, Échec : %{failure}",
+ "refresh_feeds_tooltip": "Rafraîchir les flux",
+ "refresh_feeds_title": "Rafraîchir les flux",
+ "refresh_feeds_cancel": "Annuler",
+ "refresh_feeds_error": "Flux en erreur",
+ "refresh_feeds_all": "Tous les flux",
+ "refresh_feeds_description": "Voulez-vous rafraîchir tous les flux ou uniquement ceux en erreur ?",
+ "remove_feed_success": "Flux supprimé : %{title}",
+ "remove_feed_error": "Impossible de supprimer le flux : %{title}",
+ "table_title": "Titre",
+ "table_url": "URL",
+ "table_category": "Catégorie",
+ "table_checked_at": "Vérifié à",
+ "table_actions": "Actions",
+ "table_feed_bulk_update_tooltip": "Mettre à jour en masse les hôtes",
+ "table_feed_edit_tooltip": "Éditer ce flux",
+ "table_feed_refresh_tooltip": "Rafraîchir ce flux",
+ "table_feed_remove_tooltip": "Supprimer ce flux",
+ "table_feed_remove_confirm": "Supprimer ce flux ?",
+ "update_feed_success": "Flux mis à jour avec succès",
+ "update_feed_error": "Impossible de mettre à jour le flux",
+ "modal_bulk_update_title": "Mettre à jour en masse les hôtes",
+ "modal_bulk_update_description": "Ceci mettra à jour en masse les hôtes des flux filtrés. Seulement recommandé pour RSSHub.",
+ "modal_edit_feed_title": "Éditer le flux",
+ "modal_edit_feed_submit_error": "L'URL du flux ne peut pas être vide",
+ "modal_edit_feed_category_label": "Catégorie",
+ "modal_edit_feed_title_label": "Titre",
+ "modal_edit_feed_title_placeholder": "Veuillez saisir le titre du flux",
+ "modal_edit_feed_site_url_label": "URL du site",
+ "modal_edit_feed_site_url_placeholder": "Veuillez saisir l'URL du site",
+ "modal_edit_feed_feed_url_label": "URL du flux",
+ "modal_edit_feed_feed_url_placeholder": "Veuillez saisir l'URL du flux",
+ "modal_edit_feed_hidden_label": "Masqué",
+ "modal_edit_feed_disabled_label": "Désactivé",
+ "modal_edit_feed_crawler_label": "Récupérer le contenu original",
+ "modal_edit_feed_crawler_tooltip": "Seulement affecte les articles nouvellement récupérés"
+ },
+ "category_list": {
+ "add_category_success": "Catégorie ajoutée avec succès",
+ "add_category_error": "Impossible d'ajouter la catégorie",
+ "update_category_success": "Catégorie mise à jour avec succès",
+ "update_category_error": "Impossible de mettre à jour la catégorie",
+ "remove_category_success": "Catégorie supprimée : %{title}",
+ "remove_category_error": "Impossible de supprimer la catégorie : %{title}",
+ "edit_category_title": "Éditer la catégorie",
+ "edit_category_title_label": "Titre",
+ "edit_category_title_placeholder": "Veuillez saisir le titre de la catégorie",
+ "edit_category_hidden_label": "Masqué"
+ },
+ "settings": {
+ "feeds": "Flux",
+ "categories": "Catégories",
+ "general": "Général",
+ "appearance": "Apparence",
+ "hotkeys": "Raccourcis clavier",
+ "duplicate_hotkeys": "Raccourcis clavier dupliqués, veuillez vérifier vos paramètres de raccourcis clavier",
+ "default_home_page_label": "Page d'accueil par défaut",
+ "default_home_page_description": "Quelle page afficher par défaut :",
+ "default_home_page_option_all": "Tout",
+ "default_home_page_option_today": "Aujourd'hui",
+ "default_home_page_option_starred": "Favoris",
+ "default_home_page_option_history": "Historique",
+ "entries_order_label": "Ordre des entrées",
+ "entries_order_description": "Dans quel ordre afficher les entrées :",
+ "entries_order_option_published_at": "Date de publication",
+ "entries_order_option_created_at": "Date de création",
+ "entries_per_page_label": "Entrées par page",
+ "entries_per_page_description": "Afficher combien d'entrées par page :",
+ "remove_duplicates_label": "Supprimer les doublons",
+ "remove_duplicates_description": "Supprimer automatiquement les articles en double en fonction de :",
+ "remove_duplicates_option_none": "Aucun",
+ "remove_duplicates_option_hash": "Hash",
+ "remove_duplicates_option_title": "Titre",
+ "remove_duplicates_option_url": "URL",
+ "show_unread_feeds_only_label": "Afficher uniquement les flux non lus",
+ "show_unread_feeds_only_description": "Afficher uniquement les flux non lus dans la liste des flux",
+ "mark_read_on_scroll_label": "Marquer les articles comme lus lors du défilement",
+ "mark_read_on_scroll_description": "Marquer automatiquement les articles comme lus lorsqu'ils sont défilés hors de la zone visible de l'écran"
+ },
+ "appearance": {
+ "theme_switcher_label": "Thème",
+ "theme_switcher_description": "Choisir votre thème",
+ "theme_color_label": "Couleur du thème",
+ "theme_color_description": "Choisir votre couleur de thème",
+ "theme_color_aria_label": "Changer la couleur du thème en %{color}",
+ "compact_article_card_label": "Carte d'article compacte",
+ "compact_article_card_description": "Utiliser une miniature petite dans la carte d'article",
+ "show_detailed_relative_time_label": "Afficher le temps relatif détaillé",
+ "show_detailed_relative_time_description": "Afficher le temps relatif détaillé dans la carte d'article",
+ "show_estimated_reading_time_label": "Afficher le temps de lecture estimé",
+ "show_estimated_reading_time_description": "Afficher le temps de lecture estimé dans la carte d'article",
+ "show_feed_icon_label": "Afficher l'icône du flux",
+ "show_feed_icon_description": "Afficher l'icône du flux dans la liste des flux et la carte d'article",
+ "language_label": "Langue",
+ "language_description": "Choisir votre langue :",
+ "font_size_label": "Taille de la police",
+ "font_size_description": "Ajuster la taille de la police des articles",
+ "article_width_label": "Largeur de l'article",
+ "article_width_description": "Ajuster la largeur de l'article",
+ "font_family_label": "Police de l'article",
+ "font_family_description": "Choisir votre police de l'article",
+ "font_family_system": "Par défaut",
+ "font_family_noto_sans": "Noto Sans SC",
+ "font_family_noto_serif": "Noto Serif SC",
+ "font_family_lxgw_wenkai": "LXGW WenKai Screen",
+ "title_alignment_label": "Alignement du titre de l'article",
+ "title_alignment_description": "Choisir l'alignement du titre de l'article"
+ },
+ "hotkeys": {
+ "key": "Touche",
+ "function": "Fonction",
+ "exitDetailView": "Quitter la vue détaillée et revenir à la liste",
+ "fetchOriginalArticle": "Récupérer et afficher le contenu original de l'article actuel",
+ "navigateToNextArticle": "Naviguer vers l'article suivant dans la liste",
+ "navigateToNextUnreadArticle": "Naviguer vers l'article suivant non lu dans la liste",
+ "navigateToPreviousArticle": "Naviguer vers l'article précédent dans la liste",
+ "navigateToPreviousUnreadArticle": "Naviguer vers l'article précédent non lu dans la liste",
+ "openLinkExternally": "Ouvrir le lien de l'article actuel dans un nouvel onglet du navigateur",
+ "openPhotoSlider": "Ouvrir le diaporama de photos pour afficher toutes les images de l'article actuel",
+ "saveToThirdPartyServices": "Sauvegarder l'article actuel dans les services tiers",
+ "showHotkeysSettings": "Afficher les paramètres de raccourcis clavier",
+ "toggleReadStatus": "Basculer le statut de lecture de l'article actuel",
+ "toggleStarStatus": "Basculer le statut de favori de l'article actuel"
+ },
+ "date": {
+ "just_now": "à l'instant",
+ "years": "%{smart_count} an |||| %{smart_count} ans",
+ "months": "%{smart_count} mois |||| %{smart_count} mois",
+ "days": "%{smart_count} jour |||| %{smart_count} jours",
+ "hours": "%{smart_count} heure |||| %{smart_count} heures",
+ "minutes": "%{smart_count} minute |||| %{smart_count} minutes",
+ "in_time": "dans %{time}",
+ "time_ago": "il y a %{time}"
+ }
+}
diff --git a/src/main.jsx b/src/main.jsx
index c1a59ca32..44fa41910 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -2,6 +2,7 @@ import { ConfigProvider } from "@arco-design/web-react";
import "@arco-design/web-react/dist/css/arco.css";
import enUS from "@arco-design/web-react/es/locale/en-US";
import esES from "@arco-design/web-react/es/locale/es-ES";
+import frFR from "@arco-design/web-react/es/locale/fr-FR";
import zhCN from "@arco-design/web-react/es/locale/zh-CN";
import ReactDOM from "react-dom/client";
import { RouterProvider } from "react-router-dom";
@@ -14,8 +15,9 @@ import "./theme.css";
import { getPreferredLanguage } from "./utils/locales";
const localMap = {
- "zh-CN": zhCN,
"es-ES": esES,
+ "fr-FR": frFR,
+ "zh-CN": zhCN,
};
const getLocale = () => localMap[getPreferredLanguage()] || enUS;