From 4612730474cb2b40ad22d5d0861925a5ce105b60 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Thu, 26 Dec 2024 23:29:54 +0100 Subject: [PATCH] Add i18n support (#46) --- apps/readest-app/i18next-scanner.config.js | 30 + apps/readest-app/package.json | 6 + .../public/locales/de/translation.json | 92 +++ .../public/locales/en/translation.json | 1 + .../public/locales/es/translation.json | 92 +++ .../public/locales/fr/translation.json | 92 +++ .../public/locales/it/translation.json | 92 +++ .../public/locales/ja/translation.json | 92 +++ .../public/locales/ko/translation.json | 92 +++ .../public/locales/pt/translation.json | 92 +++ .../public/locales/ru/translation.json | 92 +++ .../public/locales/tr/translation.json | 92 +++ .../public/locales/vi/translation.json | 92 +++ .../public/locales/zh-CN/translation.json | 92 +++ .../public/locales/zh-TW/translation.json | 92 +++ apps/readest-app/src/app/layout.tsx | 2 +- .../src/app/library/components/Bookshelf.tsx | 22 +- .../app/library/components/LibraryHeader.tsx | 19 +- .../app/library/components/SettingsMenu.tsx | 18 +- apps/readest-app/src/app/library/page.tsx | 10 +- .../app/reader/components/BookmarkToggler.tsx | 4 +- .../src/app/reader/components/FooterBar.tsx | 18 +- .../app/reader/components/NotebookToggler.tsx | 4 +- .../src/app/reader/components/PageInfo.tsx | 9 +- .../app/reader/components/SidebarToggler.tsx | 4 +- .../src/app/reader/components/ViewMenu.tsx | 14 +- .../app/reader/components/notebook/Header.tsx | 38 +- .../reader/components/notebook/NoteEditor.tsx | 6 +- .../reader/components/notebook/Notebook.tsx | 8 +- .../reader/components/settings/ColorPanel.tsx | 12 +- .../reader/components/settings/DialogMenu.tsx | 4 +- .../reader/components/settings/FontPanel.tsx | 20 +- .../components/settings/LayoutPanel.tsx | 20 +- .../reader/components/settings/MiscPanel.tsx | 12 +- .../components/settings/SettingsDialog.tsx | 14 +- .../reader/components/sidebar/BookCard.tsx | 6 +- .../reader/components/sidebar/BookMenu.tsx | 8 +- .../components/sidebar/BooknoteItem.tsx | 8 +- .../reader/components/sidebar/SearchBar.tsx | 4 +- .../components/sidebar/SearchOptions.tsx | 12 +- .../src/components/AboutWindow.tsx | 8 +- apps/readest-app/src/components/Alert.tsx | 6 +- apps/readest-app/src/components/Spinner.tsx | 4 +- apps/readest-app/src/hooks/useTranslation.ts | 12 + apps/readest-app/src/i18n/i18n.ts | 45 ++ apps/readest-app/src/utils/book.ts | 18 + apps/readest-app/src/utils/os.ts | 10 +- pnpm-lock.yaml | 604 +++++++++++++++++- 48 files changed, 2016 insertions(+), 128 deletions(-) create mode 100644 apps/readest-app/i18next-scanner.config.js create mode 100644 apps/readest-app/public/locales/de/translation.json create mode 100644 apps/readest-app/public/locales/en/translation.json create mode 100644 apps/readest-app/public/locales/es/translation.json create mode 100644 apps/readest-app/public/locales/fr/translation.json create mode 100644 apps/readest-app/public/locales/it/translation.json create mode 100644 apps/readest-app/public/locales/ja/translation.json create mode 100644 apps/readest-app/public/locales/ko/translation.json create mode 100644 apps/readest-app/public/locales/pt/translation.json create mode 100644 apps/readest-app/public/locales/ru/translation.json create mode 100644 apps/readest-app/public/locales/tr/translation.json create mode 100644 apps/readest-app/public/locales/vi/translation.json create mode 100644 apps/readest-app/public/locales/zh-CN/translation.json create mode 100644 apps/readest-app/public/locales/zh-TW/translation.json create mode 100644 apps/readest-app/src/hooks/useTranslation.ts create mode 100644 apps/readest-app/src/i18n/i18n.ts diff --git a/apps/readest-app/i18next-scanner.config.js b/apps/readest-app/i18next-scanner.config.js new file mode 100644 index 00000000..c48b5f8a --- /dev/null +++ b/apps/readest-app/i18next-scanner.config.js @@ -0,0 +1,30 @@ +module.exports = { + input: ['src/**/*.{js,jsx,ts,tsx}', '!src/**/*.test.{js,jsx,ts,tsx}'], + output: '.', + options: { + debug: false, + sort: true, + func: { + list: ['_'], + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, + lngs: ['de', 'ja', 'es', 'fr', 'it', 'ko', 'pt', 'ru', 'tr', 'vi', 'zh-CN', 'zh-TW'], + ns: ['translation'], + defaultNs: 'translation', + defaultValue: '__STRING_NOT_TRANSLATED__', + resource: { + loadPath: './public/locales/{{lng}}/{{ns}}.json', + savePath: './public/locales/{{lng}}/{{ns}}.json', + jsonIndent: 2, + lineEnding: '\n', + }, + keySeparator: true, + nsSeparator: false, + interpolation: { + prefix: '{{', + suffix: '}}', + }, + metadata: {}, + allowDynamicKeys: true, + }, +}; diff --git a/apps/readest-app/package.json b/apps/readest-app/package.json index 67c8e4b2..a4823bed 100644 --- a/apps/readest-app/package.json +++ b/apps/readest-app/package.json @@ -9,6 +9,7 @@ "dev-web": "dotenv -e .env.web -- next dev", "build-web": "dotenv -e .env.web -- next build", "start-web": "dotenv -e .env.web -- next start", + "i18n:extract": "i18next-scanner", "lint": "next lint", "tauri": "tauri", "prepare-public-vendor": "mkdirp ./public/vendor/pdfjs", @@ -48,11 +49,15 @@ "cors": "^2.8.5", "cssbeautify": "^0.3.1", "foliate-js": "workspace:*", + "i18next": "^24.2.0", + "i18next-browser-languagedetector": "^8.0.2", + "i18next-http-backend": "^3.0.1", "js-md5": "^0.8.3", "next": "15.1.0", "posthog-js": "^1.194.1", "react": "19.0.0", "react-dom": "19.0.0", + "react-i18next": "^15.2.0", "react-icons": "^5.3.0", "tinycolor2": "^1.6.0", "zustand": "5.0.1" @@ -71,6 +76,7 @@ "dotenv-cli": "^7.4.4", "eslint": "^9.16.0", "eslint-config-next": "15.0.3", + "i18next-scanner": "^4.6.0", "mkdirp": "^3.0.1", "node-env-run": "^4.0.2", "postcss": "^8.4.49", diff --git a/apps/readest-app/public/locales/de/translation.json b/apps/readest-app/public/locales/de/translation.json new file mode 100644 index 00000000..24ec9b11 --- /dev/null +++ b/apps/readest-app/public/locales/de/translation.json @@ -0,0 +1,92 @@ +{ + "About Readest": "Über Readest", + "Add your notes here...": "Fügen Sie hier Ihre Notizen hinzu...", + "Animation": "Animation", + "Auto Mode": "Automatischer Modus", + "Behavior": "Verhalten", + "Book": "Buch", + "Book Cover": "Buchcover", + "Bookmark": "Lesezeichen", + "Cancel": "Abbrechen", + "Chapter": "Kapitel", + "Color": "Farbe", + "Confirm": "Bestätigen", + "Confirm Deletion": "Löschen bestätigen", + "Custom CSS": "Benutzerdefiniertes CSS", + "Dark Mode": "Dunkelmodus", + "Default Font": "Standardschriftart", + "Delete": "Löschen", + "Disable Click-to-Flip": "Klick zum Blättern deaktivieren", + "Download Readest": "Readest herunterladen", + "Edit": "Bearbeiten", + "Excerpts": "Auszüge", + "Font": "Schriftart", + "Font & Layout": "Schrift & Layout", + "Font Face": "Schriftschnitt", + "Font Family": "Schriftfamilie", + "Font Size": "Schriftgröße", + "From Local File": "Aus lokaler Datei", + "Full Justification": "Blocksatz", + "Gaps (%)": "Abstände (%)", + "Global Settings": "Globale Einstellungen", + "Go Back": "Zurück", + "Go Forward": "Vorwärts", + "Go Left": "Nach links", + "Go Right": "Nach rechts", + "Hyphenation": "Silbentrennung", + "Identifier:": "Kennung:", + "Import Books": "Bücher importieren", + "Invert Colors in Dark Mode": "Farben im Dunkelmodus invertieren", + "Language:": "Sprache:", + "Layout": "Layout", + "Light Mode": "Hellmodus", + "Loading...": "Wird geladen...", + "Loc. {{currentPage}} / {{totalPage}}": "Pos. {{currentPage}} / {{totalPage}}", + "Logged in": "Angemeldet", + "Logged in as {{userDisplayName}}": "Angemeldet als {{userDisplayName}}", + "Margins (px)": "Ränder (px)", + "Match Case": "Groß-/Kleinschreibung beachten", + "Match Diacritics": "Akzente beachten", + "Match Whole Words": "Ganze Wörter", + "Maximum Block Size": "Maximale Blockgröße", + "Maximum Inline Size": "Maximale Zeilengröße", + "Maximum Number of Columns": "Maximale Spaltenanzahl", + "Misc": "Sonstiges", + "Monospace Font": "Monospace-Schriftart", + "More Info": "Weitere Informationen", + "Notebook": "Notizbuch", + "Notes": "Notizen", + "Open": "Öffnen", + "Override Publisher Font": "Verleger-Schriftart überschreiben", + "Page": "Seite", + "Paging Animation": "Blätter-Animation", + "Paragraph": "Absatz", + "Parallel Read": "Paralleles Lesen", + "Published:": "Veröffentlicht:", + "Publisher:": "Verlag:", + "Reload Page": "Seite neu laden", + "Reveal in File Explorer": "Im Datei-Explorer anzeigen", + "Reveal in Finder": "Im Finder anzeigen", + "Reveal in Folder": "Im Ordner anzeigen", + "Sans-Serif Font": "Serifenlose Schriftart", + "Save": "Speichern", + "Scrolled Mode": "Scroll-Modus", + "Search books...": "Bücher suchen...", + "Search...": "Suchen...", + "Select books": "Bücher auswählen", + "Select multiple books": "Mehrere Bücher auswählen", + "Serif Font": "Serifenschrift", + "Sidebar": "Seitenleiste", + "Sign In": "Anmelden", + "Sign Out": "Abmelden", + "Subjects:": "Themen:", + "Theme Color": "Themenfarbe", + "Theme Mode": "Themenmodus", + "Unknown": "Unbekannt", + "Untitled": "Ohne Titel", + "Updated:": "Aktualisiert:", + "User avatar": "Benutzer-Avatar", + "Version {{version}}": "Version {{version}}", + "Welcome to your library. You can import your books here and read them anytime.": "Willkommen in Ihrer Bibliothek. Sie können hier Ihre Bücher importieren und jederzeit lesen.", + "Your Library": "Ihre Bibliothek" +} diff --git a/apps/readest-app/public/locales/en/translation.json b/apps/readest-app/public/locales/en/translation.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/apps/readest-app/public/locales/en/translation.json @@ -0,0 +1 @@ +{} diff --git a/apps/readest-app/public/locales/es/translation.json b/apps/readest-app/public/locales/es/translation.json new file mode 100644 index 00000000..5bb4c440 --- /dev/null +++ b/apps/readest-app/public/locales/es/translation.json @@ -0,0 +1,92 @@ +{ + "About Readest": "Acerca de Readest", + "Add your notes here...": "Añade tus notas aquí...", + "Animation": "Animación", + "Auto Mode": "Modo automático", + "Behavior": "Comportamiento", + "Book": "Libro", + "Book Cover": "Portada del libro", + "Bookmark": "Marcador", + "Cancel": "Cancelar", + "Chapter": "Capítulo", + "Color": "Color", + "Confirm": "Confirmar", + "Confirm Deletion": "Confirmar eliminación", + "Custom CSS": "CSS personalizado", + "Dark Mode": "Modo oscuro", + "Default Font": "Fuente predeterminada", + "Delete": "Eliminar", + "Disable Click-to-Flip": "Desactivar clic para voltear", + "Download Readest": "Descargar Readest", + "Edit": "Editar", + "Excerpts": "Extractos", + "Font": "Fuente", + "Font & Layout": "Fuente y diseño", + "Font Face": "Tipo de fuente", + "Font Family": "Familia de fuente", + "Font Size": "Tamaño de fuente", + "From Local File": "Desde archivo local", + "Full Justification": "Justificación completa", + "Gaps (%)": "Espacios (%)", + "Global Settings": "Configuración global", + "Go Back": "Volver", + "Go Forward": "Avanzar", + "Go Left": "Ir a la izquierda", + "Go Right": "Ir a la derecha", + "Hyphenation": "Guionización", + "Identifier:": "Identificador:", + "Import Books": "Importar libros", + "Invert Colors in Dark Mode": "Invertir colores en modo oscuro", + "Language:": "Idioma:", + "Layout": "Diseño", + "Light Mode": "Modo claro", + "Loading...": "Cargando...", + "Loc. {{currentPage}} / {{totalPage}}": "Pos. {{currentPage}} / {{totalPage}}", + "Logged in": "Sesión iniciada", + "Logged in as {{userDisplayName}}": "Sesión iniciada como {{userDisplayName}}", + "Margins (px)": "Márgenes (px)", + "Match Case": "Coincidir mayúsculas y minúsculas", + "Match Diacritics": "Coincidir diacríticos", + "Match Whole Words": "Coincidir palabras completas", + "Maximum Block Size": "Tamaño máximo de bloque", + "Maximum Inline Size": "Tamaño máximo en línea", + "Maximum Number of Columns": "Número máximo de columnas", + "Misc": "Varios", + "Monospace Font": "Fuente monoespaciada", + "More Info": "Más información", + "Notebook": "Cuaderno", + "Notes": "Notas", + "Open": "Abrir", + "Override Publisher Font": "Sobrescribir fuente del editor", + "Page": "Página", + "Paging Animation": "Animación de paginación", + "Paragraph": "Párrafo", + "Parallel Read": "Lectura paralela", + "Published:": "Publicado:", + "Publisher:": "Editorial:", + "Reload Page": "Recargar página", + "Reveal in File Explorer": "Mostrar en el Explorador de archivos", + "Reveal in Finder": "Mostrar en Finder", + "Reveal in Folder": "Mostrar en carpeta", + "Sans-Serif Font": "Fuente sans-serif", + "Save": "Guardar", + "Scrolled Mode": "Modo desplazamiento", + "Search books...": "Buscar libros...", + "Search...": "Buscar...", + "Select books": "Seleccionar libros", + "Select multiple books": "Seleccionar varios libros", + "Serif Font": "Fuente serif", + "Sidebar": "Barra lateral", + "Sign In": "Iniciar sesión", + "Sign Out": "Cerrar sesión", + "Subjects:": "Temas:", + "Theme Color": "Color del tema", + "Theme Mode": "Modo del tema", + "Unknown": "Desconocido", + "Untitled": "Sin título", + "Updated:": "Actualizado:", + "User avatar": "Avatar del usuario", + "Version {{version}}": "Versión {{version}}", + "Welcome to your library. You can import your books here and read them anytime.": "Bienvenido a tu biblioteca. Puedes importar tus libros aquí y leerlos en cualquier momento.", + "Your Library": "Tu biblioteca" +} diff --git a/apps/readest-app/public/locales/fr/translation.json b/apps/readest-app/public/locales/fr/translation.json new file mode 100644 index 00000000..40247aae --- /dev/null +++ b/apps/readest-app/public/locales/fr/translation.json @@ -0,0 +1,92 @@ +{ + "About Readest": "À propos de Readest", + "Add your notes here...": "Ajoutez vos notes ici...", + "Animation": "Animation", + "Auto Mode": "Mode automatique", + "Behavior": "Comportement", + "Book": "Livre", + "Book Cover": "Couverture du livre", + "Bookmark": "Signet", + "Cancel": "Annuler", + "Chapter": "Chapitre", + "Color": "Couleur", + "Confirm": "Confirmer", + "Confirm Deletion": "Confirmer la suppression", + "Custom CSS": "CSS personnalisé", + "Dark Mode": "Mode sombre", + "Default Font": "Police par défaut", + "Delete": "Supprimer", + "Disable Click-to-Flip": "Désactiver le clic pour tourner", + "Download Readest": "Télécharger Readest", + "Edit": "Modifier", + "Excerpts": "Extraits", + "Font": "Police", + "Font & Layout": "Police et mise en page", + "Font Face": "Style de police", + "Font Family": "Famille de police", + "Font Size": "Taille de police", + "From Local File": "Depuis un fichier local", + "Full Justification": "Justification complète", + "Gaps (%)": "Espaces (%)", + "Global Settings": "Paramètres globaux", + "Go Back": "Retour", + "Go Forward": "Avancer", + "Go Left": "Aller à gauche", + "Go Right": "Aller à droite", + "Hyphenation": "Césure", + "Identifier:": "Identifiant :", + "Import Books": "Importer des livres", + "Invert Colors in Dark Mode": "Inverser les couleurs en mode sombre", + "Language:": "Langue :", + "Layout": "Mise en page", + "Light Mode": "Mode clair", + "Loading...": "Chargement...", + "Loc. {{currentPage}} / {{totalPage}}": "Pos. {{currentPage}} / {{totalPage}}", + "Logged in": "Connecté", + "Logged in as {{userDisplayName}}": "Connecté en tant que {{userDisplayName}}", + "Margins (px)": "Marges (px)", + "Match Case": "Respecter la casse", + "Match Diacritics": "Respecter les accents", + "Match Whole Words": "Mots entiers", + "Maximum Block Size": "Taille maximale du bloc", + "Maximum Inline Size": "Taille maximale en ligne", + "Maximum Number of Columns": "Nombre maximal de colonnes", + "Misc": "Divers", + "Monospace Font": "Police monospace", + "More Info": "Plus d'informations", + "Notebook": "Carnet de notes", + "Notes": "Notes", + "Open": "Ouvrir", + "Override Publisher Font": "Remplacer la police de l'éditeur", + "Page": "Page", + "Paging Animation": "Animation de page", + "Paragraph": "Paragraphe", + "Parallel Read": "Lecture parallèle", + "Published:": "Publié :", + "Publisher:": "Éditeur :", + "Reload Page": "Recharger la page", + "Reveal in File Explorer": "Afficher dans l'explorateur de fichiers", + "Reveal in Finder": "Afficher dans le Finder", + "Reveal in Folder": "Afficher dans le dossier", + "Sans-Serif Font": "Police sans empattement", + "Save": "Enregistrer", + "Scrolled Mode": "Mode défilement", + "Search books...": "Rechercher des livres...", + "Search...": "Rechercher...", + "Select books": "Sélectionner des livres", + "Select multiple books": "Sélectionner plusieurs livres", + "Serif Font": "Police avec empattement", + "Sidebar": "Barre latérale", + "Sign In": "Se connecter", + "Sign Out": "Se déconnecter", + "Subjects:": "Sujets :", + "Theme Color": "Couleur du thème", + "Theme Mode": "Mode du thème", + "Unknown": "Inconnu", + "Untitled": "Sans titre", + "Updated:": "Mis à jour :", + "User avatar": "Avatar de l'utilisateur", + "Version {{version}}": "Version {{version}}", + "Welcome to your library. You can import your books here and read them anytime.": "Bienvenue dans votre bibliothèque. Vous pouvez importer vos livres ici et les lire à tout moment.", + "Your Library": "Votre bibliothèque" +} diff --git a/apps/readest-app/public/locales/it/translation.json b/apps/readest-app/public/locales/it/translation.json new file mode 100644 index 00000000..47a6efad --- /dev/null +++ b/apps/readest-app/public/locales/it/translation.json @@ -0,0 +1,92 @@ +{ + "About Readest": "Informazioni su Readest", + "Add your notes here...": "Aggiungi qui le tue note...", + "Animation": "Animazione", + "Auto Mode": "Modalità automatica", + "Behavior": "Comportamento", + "Book": "Libro", + "Book Cover": "Copertina", + "Bookmark": "Segnalibro", + "Cancel": "Annulla", + "Chapter": "Capitolo", + "Color": "Colore", + "Confirm": "Conferma", + "Confirm Deletion": "Conferma eliminazione", + "Custom CSS": "CSS personalizzato", + "Dark Mode": "Modalità scura", + "Default Font": "Font predefinito", + "Delete": "Elimina", + "Disable Click-to-Flip": "Disattiva click per voltare pagina", + "Download Readest": "Scarica Readest", + "Edit": "Modifica", + "Excerpts": "Estratti", + "Font": "Font", + "Font & Layout": "Font e Layout", + "Font Face": "Tipo di carattere", + "Font Family": "Famiglia di caratteri", + "Font Size": "Dimensione carattere", + "From Local File": "Da file locale", + "Full Justification": "Giustificazione completa", + "Gaps (%)": "Spaziature (%)", + "Global Settings": "Impostazioni globali", + "Go Back": "Indietro", + "Go Forward": "Avanti", + "Go Left": "Vai a sinistra", + "Go Right": "Vai a destra", + "Hyphenation": "Sillabazione", + "Identifier:": "Identificatore:", + "Import Books": "Importa libri", + "Invert Colors in Dark Mode": "Inverti colori in modalità scura", + "Language:": "Lingua:", + "Layout": "Layout", + "Light Mode": "Modalità chiara", + "Loading...": "Caricamento...", + "Loc. {{currentPage}} / {{totalPage}}": "Pos. {{currentPage}} / {{totalPage}}", + "Logged in": "Accesso effettuato", + "Logged in as {{userDisplayName}}": "Accesso effettuato come {{userDisplayName}}", + "Margins (px)": "Margini (px)", + "Match Case": "Maiuscole/minuscole", + "Match Diacritics": "Corrispondenza diacritici", + "Match Whole Words": "Parole intere", + "Maximum Block Size": "Dimensione massima blocco", + "Maximum Inline Size": "Dimensione massima in linea", + "Maximum Number of Columns": "Numero massimo di colonne", + "Misc": "Varie", + "Monospace Font": "Font monospazio", + "More Info": "Maggiori informazioni", + "Notebook": "Quaderno", + "Notes": "Note", + "Open": "Apri", + "Override Publisher Font": "Sostituisci font editore", + "Page": "Pagina", + "Paging Animation": "Animazione cambio pagina", + "Paragraph": "Paragrafo", + "Parallel Read": "Lettura parallela", + "Published:": "Pubblicato:", + "Publisher:": "Editore:", + "Reload Page": "Ricarica pagina", + "Reveal in File Explorer": "Mostra in Esplora file", + "Reveal in Finder": "Mostra nel Finder", + "Reveal in Folder": "Mostra nella cartella", + "Sans-Serif Font": "Font sans-serif", + "Save": "Salva", + "Scrolled Mode": "Modalità scorrimento", + "Search books...": "Cerca libri...", + "Search...": "Cerca...", + "Select books": "Seleziona libri", + "Select multiple books": "Seleziona più libri", + "Serif Font": "Font serif", + "Sidebar": "Barra laterale", + "Sign In": "Accedi", + "Sign Out": "Esci", + "Subjects:": "Argomenti:", + "Theme Color": "Colore tema", + "Theme Mode": "Modalità tema", + "Unknown": "Sconosciuto", + "Untitled": "Senza titolo", + "Updated:": "Aggiornato:", + "User avatar": "Avatar utente", + "Version {{version}}": "Versione {{version}}", + "Welcome to your library. You can import your books here and read them anytime.": "Benvenuto nella tua biblioteca. Puoi importare i tuoi libri qui e leggerli in qualsiasi momento.", + "Your Library": "La tua biblioteca" +} diff --git a/apps/readest-app/public/locales/ja/translation.json b/apps/readest-app/public/locales/ja/translation.json new file mode 100644 index 00000000..281c0336 --- /dev/null +++ b/apps/readest-app/public/locales/ja/translation.json @@ -0,0 +1,92 @@ +{ + "About Readest": "Readestについて", + "Add your notes here...": "ここにメモを追加...", + "Animation": "アニメーション", + "Auto Mode": "自動モード", + "Behavior": "動作", + "Book": "書籍", + "Book Cover": "表紙", + "Bookmark": "ブックマーク", + "Cancel": "キャンセル", + "Chapter": "章", + "Color": "色", + "Confirm": "確認", + "Confirm Deletion": "削除の確認", + "Custom CSS": "カスタムCSS", + "Dark Mode": "ダークモード", + "Default Font": "デフォルトフォント", + "Delete": "削除", + "Disable Click-to-Flip": "クリックめくりを無効化", + "Download Readest": "Readestをダウンロード", + "Edit": "編集", + "Excerpts": "抜粋", + "Font": "フォント", + "Font & Layout": "フォントとレイアウト", + "Font Face": "書体", + "Font Family": "フォントファミリー", + "Font Size": "フォントサイズ", + "From Local File": "ローカルファイルから", + "Full Justification": "両端揃え", + "Gaps (%)": "間隔 (%)", + "Global Settings": "全体設定", + "Go Back": "戻る", + "Go Forward": "進む", + "Go Left": "左へ", + "Go Right": "右へ", + "Hyphenation": "ハイフネーション", + "Identifier:": "識別子:", + "Import Books": "書籍をインポート", + "Invert Colors in Dark Mode": "ダークモードで色を反転", + "Language:": "言語:", + "Layout": "レイアウト", + "Light Mode": "ライトモード", + "Loading...": "読み込み中...", + "Loc. {{currentPage}} / {{totalPage}}": "位置 {{currentPage}} / {{totalPage}}", + "Logged in": "ログイン済み", + "Logged in as {{userDisplayName}}": "{{userDisplayName}}としてログイン中", + "Margins (px)": "余白 (px)", + "Match Case": "大文字・小文字を区別", + "Match Diacritics": "アクセント記号を区別", + "Match Whole Words": "単語全体を一致", + "Maximum Block Size": "最大ブロックサイズ", + "Maximum Inline Size": "最大インラインサイズ", + "Maximum Number of Columns": "最大列数", + "Misc": "その他", + "Monospace Font": "等幅フォント", + "More Info": "詳細情報", + "Notebook": "ノート", + "Notes": "メモ", + "Open": "開く", + "Override Publisher Font": "出版社フォントを上書き", + "Page": "ページ", + "Paging Animation": "ページめくりアニメーション", + "Paragraph": "段落", + "Parallel Read": "並列読書", + "Published:": "出版日:", + "Publisher:": "出版社:", + "Reload Page": "ページを再読み込み", + "Reveal in File Explorer": "エクスプローラーで表示", + "Reveal in Finder": "Finderで表示", + "Reveal in Folder": "フォルダーで表示", + "Sans-Serif Font": "ゴシック体", + "Save": "保存", + "Scrolled Mode": "スクロールモード", + "Search books...": "書籍を検索...", + "Search...": "検索...", + "Select books": "書籍を選択", + "Select multiple books": "複数の書籍を選択", + "Serif Font": "明朝体", + "Sidebar": "サイドバー", + "Sign In": "サインイン", + "Sign Out": "サインアウト", + "Subjects:": "主題:", + "Theme Color": "テーマカラー", + "Theme Mode": "テーマモード", + "Unknown": "不明", + "Untitled": "無題", + "Updated:": "更新日:", + "User avatar": "ユーザーアバター", + "Version {{version}}": "バージョン {{version}}", + "Welcome to your library. You can import your books here and read them anytime.": "ライブラリーへようこそ。ここに書籍をインポートして、いつでも読むことができます。", + "Your Library": "ライブラリー" +} diff --git a/apps/readest-app/public/locales/ko/translation.json b/apps/readest-app/public/locales/ko/translation.json new file mode 100644 index 00000000..a54b24c8 --- /dev/null +++ b/apps/readest-app/public/locales/ko/translation.json @@ -0,0 +1,92 @@ +{ + "About Readest": "Readest 정보", + "Add your notes here...": "여기에 메모를 추가하세요...", + "Animation": "애니메이션", + "Auto Mode": "자동 모드", + "Behavior": "동작", + "Book": "책", + "Book Cover": "책 표지", + "Bookmark": "북마크", + "Cancel": "취소", + "Chapter": "챕터", + "Color": "색상", + "Confirm": "확인", + "Confirm Deletion": "삭제 확인", + "Custom CSS": "사용자 정의 CSS", + "Dark Mode": "다크 모드", + "Default Font": "기본 글꼴", + "Delete": "삭제", + "Disable Click-to-Flip": "클릭 넘기기 비활성화", + "Download Readest": "Readest 다운로드", + "Edit": "편집", + "Excerpts": "발췌", + "Font": "글꼴", + "Font & Layout": "글꼴 및 레이아웃", + "Font Face": "글꼴 스타일", + "Font Family": "글꼴 패밀리", + "Font Size": "글꼴 크기", + "From Local File": "로컬 파일에서", + "Full Justification": "양쪽 정렬", + "Gaps (%)": "간격 (%)", + "Global Settings": "전역 설정", + "Go Back": "뒤로", + "Go Forward": "앞으로", + "Go Left": "왼쪽으로", + "Go Right": "오른쪽으로", + "Hyphenation": "하이픈 넣기", + "Identifier:": "식별자:", + "Import Books": "책 가져오기", + "Invert Colors in Dark Mode": "다크 모드에서 색상 반전", + "Language:": "언어:", + "Layout": "레이아웃", + "Light Mode": "라이트 모드", + "Loading...": "로딩 중...", + "Loc. {{currentPage}} / {{totalPage}}": "위치 {{currentPage}} / {{totalPage}}", + "Logged in": "로그인됨", + "Logged in as {{userDisplayName}}": "{{userDisplayName}}(으)로 로그인됨", + "Margins (px)": "여백 (px)", + "Match Case": "대소문자 구분", + "Match Diacritics": "발음 구별 부호 구분", + "Match Whole Words": "전체 단어 일치", + "Maximum Block Size": "최대 블록 크기", + "Maximum Inline Size": "최대 인라인 크기", + "Maximum Number of Columns": "최대 열 수", + "Misc": "기타", + "Monospace Font": "고정폭 글꼴", + "More Info": "추가 정보", + "Notebook": "노트북", + "Notes": "메모", + "Open": "열기", + "Override Publisher Font": "출판사 글꼴 재정의", + "Page": "페이지", + "Paging Animation": "페이지 넘김 애니메이션", + "Paragraph": "단락", + "Parallel Read": "병렬 읽기", + "Published:": "출판일:", + "Publisher:": "출판사:", + "Reload Page": "페이지 새로고침", + "Reveal in File Explorer": "파일 탐색기에서 표시", + "Reveal in Finder": "Finder에서 표시", + "Reveal in Folder": "폴더에서 표시", + "Sans-Serif Font": "산세리프체", + "Save": "저장", + "Scrolled Mode": "스크롤 모드", + "Search books...": "책 검색...", + "Search...": "검색...", + "Select books": "책 선택", + "Select multiple books": "여러 책 선택", + "Serif Font": "세리프체", + "Sidebar": "사이드바", + "Sign In": "로그인", + "Sign Out": "로그아웃", + "Subjects:": "주제:", + "Theme Color": "테마 색상", + "Theme Mode": "테마 모드", + "Unknown": "알 수 없음", + "Untitled": "제목 없음", + "Updated:": "업데이트일:", + "User avatar": "사용자 아바타", + "Version {{version}}": "버전 {{version}}", + "Welcome to your library. You can import your books here and read them anytime.": "내 서재에 오신 것을 환영합니다. 여기에서 책을 가져와 언제든지 읽을 수 있습니다.", + "Your Library": "내 서재" +} diff --git a/apps/readest-app/public/locales/pt/translation.json b/apps/readest-app/public/locales/pt/translation.json new file mode 100644 index 00000000..90aebfc2 --- /dev/null +++ b/apps/readest-app/public/locales/pt/translation.json @@ -0,0 +1,92 @@ +{ + "About Readest": "Sobre o Readest", + "Add your notes here...": "Adicione suas notas aqui...", + "Animation": "Animação", + "Auto Mode": "Modo Automático", + "Behavior": "Comportamento", + "Book": "Livro", + "Book Cover": "Capa do Livro", + "Bookmark": "Marcador", + "Cancel": "Cancelar", + "Chapter": "Capítulo", + "Color": "Cor", + "Confirm": "Confirmar", + "Confirm Deletion": "Confirmar Exclusão", + "Custom CSS": "CSS Personalizado", + "Dark Mode": "Modo Escuro", + "Default Font": "Fonte Padrão", + "Delete": "Excluir", + "Disable Click-to-Flip": "Desativar Clique para Virar", + "Download Readest": "Baixar Readest", + "Edit": "Editar", + "Excerpts": "Trechos", + "Font": "Fonte", + "Font & Layout": "Fonte e Layout", + "Font Face": "Estilo da Fonte", + "Font Family": "Família da Fonte", + "Font Size": "Tamanho da Fonte", + "From Local File": "Do Arquivo Local", + "Full Justification": "Justificação Completa", + "Gaps (%)": "Espaçamentos (%)", + "Global Settings": "Configurações Globais", + "Go Back": "Voltar", + "Go Forward": "Avançar", + "Go Left": "Ir para Esquerda", + "Go Right": "Ir para Direita", + "Hyphenation": "Hifenização", + "Identifier:": "Identificador:", + "Import Books": "Importar Livros", + "Invert Colors in Dark Mode": "Inverter Cores no Modo Escuro", + "Language:": "Idioma:", + "Layout": "Layout", + "Light Mode": "Modo Claro", + "Loading...": "Carregando...", + "Loc. {{currentPage}} / {{totalPage}}": "Loc. {{currentPage}} / {{totalPage}}", + "Logged in": "Conectado", + "Logged in as {{userDisplayName}}": "Conectado como {{userDisplayName}}", + "Margins (px)": "Margens (px)", + "Match Case": "Diferenciar Maiúsculas e Minúsculas", + "Match Diacritics": "Corresponder Acentos", + "Match Whole Words": "Corresponder Palavras Inteiras", + "Maximum Block Size": "Tamanho Máximo do Bloco", + "Maximum Inline Size": "Tamanho Máximo em Linha", + "Maximum Number of Columns": "Número Máximo de Colunas", + "Misc": "Diversos", + "Monospace Font": "Fonte Monoespaçada", + "More Info": "Mais Informações", + "Notebook": "Caderno", + "Notes": "Notas", + "Open": "Abrir", + "Override Publisher Font": "Substituir Fonte do Editor", + "Page": "Página", + "Paging Animation": "Animação de Página", + "Paragraph": "Parágrafo", + "Parallel Read": "Leitura Paralela", + "Published:": "Publicado:", + "Publisher:": "Editora:", + "Reload Page": "Recarregar Página", + "Reveal in File Explorer": "Mostrar no Explorador de Arquivos", + "Reveal in Finder": "Mostrar no Finder", + "Reveal in Folder": "Mostrar na Pasta", + "Sans-Serif Font": "Fonte Sans-Serif", + "Save": "Salvar", + "Scrolled Mode": "Modo de Rolagem", + "Search books...": "Procurar livros...", + "Search...": "Pesquisar...", + "Select books": "Selecionar livros", + "Select multiple books": "Selecionar múltiplos livros", + "Serif Font": "Fonte Serif", + "Sidebar": "Barra Lateral", + "Sign In": "Entrar", + "Sign Out": "Sair", + "Subjects:": "Assuntos:", + "Theme Color": "Cor do Tema", + "Theme Mode": "Modo do Tema", + "Unknown": "Desconhecido", + "Untitled": "Sem Título", + "Updated:": "Atualizado:", + "User avatar": "Avatar do usuário", + "Version {{version}}": "Versão {{version}}", + "Welcome to your library. You can import your books here and read them anytime.": "Bem-vindo à sua biblioteca. Você pode importar seus livros aqui e lê-los a qualquer momento.", + "Your Library": "Sua Biblioteca" +} diff --git a/apps/readest-app/public/locales/ru/translation.json b/apps/readest-app/public/locales/ru/translation.json new file mode 100644 index 00000000..49c32e0f --- /dev/null +++ b/apps/readest-app/public/locales/ru/translation.json @@ -0,0 +1,92 @@ +{ + "About Readest": "О Readest", + "Add your notes here...": "Добавьте свои заметки здесь...", + "Animation": "Анимация", + "Auto Mode": "Автоматический режим", + "Behavior": "Поведение", + "Book": "Книга", + "Book Cover": "Обложка книги", + "Bookmark": "Закладка", + "Cancel": "Отмена", + "Chapter": "Глава", + "Color": "Цвет", + "Confirm": "Подтвердить", + "Confirm Deletion": "Подтвердить удаление", + "Custom CSS": "Пользовательский CSS", + "Dark Mode": "Тёмная тема", + "Default Font": "Шрифт по умолчанию", + "Delete": "Удалить", + "Disable Click-to-Flip": "Отключить переворот по клику", + "Download Readest": "Скачать Readest", + "Edit": "Редактировать", + "Excerpts": "Отрывки", + "Font": "Шрифт", + "Font & Layout": "Шрифт и макет", + "Font Face": "Начертание шрифта", + "Font Family": "Семейство шрифтов", + "Font Size": "Размер шрифта", + "From Local File": "Из локального файла", + "Full Justification": "Полное выравнивание", + "Gaps (%)": "Промежутки (%)", + "Global Settings": "Общие настройки", + "Go Back": "Назад", + "Go Forward": "Вперёд", + "Go Left": "Влево", + "Go Right": "Вправо", + "Hyphenation": "Перенос слов", + "Identifier:": "Идентификатор:", + "Import Books": "Импорт книг", + "Invert Colors in Dark Mode": "Инвертировать цвета в тёмной теме", + "Language:": "Язык:", + "Layout": "Макет", + "Light Mode": "Светлая тема", + "Loading...": "Загрузка...", + "Loc. {{currentPage}} / {{totalPage}}": "Поз. {{currentPage}} / {{totalPage}}", + "Logged in": "Выполнен вход", + "Logged in as {{userDisplayName}}": "Вход выполнен как {{userDisplayName}}", + "Margins (px)": "Отступы (px)", + "Match Case": "Учитывать регистр", + "Match Diacritics": "Учитывать диакритические знаки", + "Match Whole Words": "Только целые слова", + "Maximum Block Size": "Максимальный размер блока", + "Maximum Inline Size": "Максимальный размер строки", + "Maximum Number of Columns": "Максимальное количество колонок", + "Misc": "Разное", + "Monospace Font": "Моноширинный шрифт", + "More Info": "Подробнее", + "Notebook": "Блокнот", + "Notes": "Заметки", + "Open": "Открыть", + "Override Publisher Font": "Переопределить шрифт издателя", + "Page": "Страница", + "Paging Animation": "Анимация перелистывания", + "Paragraph": "Абзац", + "Parallel Read": "Параллельное чтение", + "Published:": "Опубликовано:", + "Publisher:": "Издатель:", + "Reload Page": "Перезагрузить страницу", + "Reveal in File Explorer": "Показать в проводнике", + "Reveal in Finder": "Показать в Finder", + "Reveal in Folder": "Показать в папке", + "Sans-Serif Font": "Шрифт без засечек", + "Save": "Сохранить", + "Scrolled Mode": "Режим прокрутки", + "Search books...": "Поиск книг...", + "Search...": "Поиск...", + "Select books": "Выбрать книги", + "Select multiple books": "Выбрать несколько книг", + "Serif Font": "Шрифт с засечками", + "Sidebar": "Боковая панель", + "Sign In": "Войти", + "Sign Out": "Выйти", + "Subjects:": "Темы:", + "Theme Color": "Цвет темы", + "Theme Mode": "Режим темы", + "Unknown": "Неизвестно", + "Untitled": "Без названия", + "Updated:": "Обновлено:", + "User avatar": "Аватар пользователя", + "Version {{version}}": "Версия {{version}}", + "Welcome to your library. You can import your books here and read them anytime.": "Добро пожаловать в вашу библиотеку. Вы можете импортировать сюда книги и читать их в любое время.", + "Your Library": "Ваша библиотека" +} diff --git a/apps/readest-app/public/locales/tr/translation.json b/apps/readest-app/public/locales/tr/translation.json new file mode 100644 index 00000000..84bbf5fa --- /dev/null +++ b/apps/readest-app/public/locales/tr/translation.json @@ -0,0 +1,92 @@ +{ + "About Readest": "Readest Hakkında", + "Add your notes here...": "Notlarınızı buraya ekleyin...", + "Animation": "Animasyon", + "Auto Mode": "Otomatik Mod", + "Behavior": "Davranış", + "Book": "Kitap", + "Book Cover": "Kitap Kapağı", + "Bookmark": "Yer İmi", + "Cancel": "İptal", + "Chapter": "Bölüm", + "Color": "Renk", + "Confirm": "Onayla", + "Confirm Deletion": "Silmeyi Onayla", + "Custom CSS": "Özel CSS", + "Dark Mode": "Karanlık Mod", + "Default Font": "Varsayılan Yazı Tipi", + "Delete": "Sil", + "Disable Click-to-Flip": "Tıkla-Çevir'i Devre Dışı Bırak", + "Download Readest": "Readest'i İndir", + "Edit": "Düzenle", + "Excerpts": "Alıntılar", + "Font": "Yazı Tipi", + "Font & Layout": "Yazı Tipi ve Düzen", + "Font Face": "Yazı Tipi Yüzü", + "Font Family": "Yazı Tipi Ailesi", + "Font Size": "Yazı Boyutu", + "From Local File": "Yerel Dosyadan", + "Full Justification": "Tam Hizalama", + "Gaps (%)": "Boşluklar (%)", + "Global Settings": "Genel Ayarlar", + "Go Back": "Geri Git", + "Go Forward": "İleri Git", + "Go Left": "Sola Git", + "Go Right": "Sağa Git", + "Hyphenation": "Heceleme", + "Identifier:": "Tanımlayıcı:", + "Import Books": "Kitapları İçe Aktar", + "Invert Colors in Dark Mode": "Karanlık Modda Renkleri Ters Çevir", + "Language:": "Dil:", + "Layout": "Düzen", + "Light Mode": "Aydınlık Mod", + "Loading...": "Yükleniyor...", + "Loc. {{currentPage}} / {{totalPage}}": "Konum {{currentPage}} / {{totalPage}}", + "Logged in": "Giriş Yapıldı", + "Logged in as {{userDisplayName}}": "{{userDisplayName}} olarak giriş yapıldı", + "Margins (px)": "Kenar Boşlukları (px)", + "Match Case": "Büyük/Küçük Harf Eşleştir", + "Match Diacritics": "Aksan İşaretlerini Eşleştir", + "Match Whole Words": "Tam Kelimeleri Eşleştir", + "Maximum Block Size": "Maksimum Blok Boyutu", + "Maximum Inline Size": "Maksimum Satır İçi Boyut", + "Maximum Number of Columns": "Maksimum Sütun Sayısı", + "Misc": "Diğer", + "Monospace Font": "Eş Aralıklı Yazı Tipi", + "More Info": "Daha Fazla Bilgi", + "Notebook": "Not Defteri", + "Notes": "Notlar", + "Open": "Aç", + "Override Publisher Font": "Yayıncı Yazı Tipini Geçersiz Kıl", + "Page": "Sayfa", + "Paging Animation": "Sayfa Çevirme Animasyonu", + "Paragraph": "Paragraf", + "Parallel Read": "Paralel Okuma", + "Published:": "Yayınlanma:", + "Publisher:": "Yayıncı:", + "Reload Page": "Sayfayı Yenile", + "Reveal in File Explorer": "Dosya Gezgininde Göster", + "Reveal in Finder": "Finder'da Göster", + "Reveal in Folder": "Klasörde Göster", + "Sans-Serif Font": "Sans-Serif Yazı Tipi", + "Save": "Kaydet", + "Scrolled Mode": "Kaydırma Modu", + "Search books...": "Kitap ara...", + "Search...": "Ara...", + "Select books": "Kitapları seç", + "Select multiple books": "Birden fazla kitap seç", + "Serif Font": "Serif Yazı Tipi", + "Sidebar": "Kenar Çubuğu", + "Sign In": "Giriş Yap", + "Sign Out": "Çıkış Yap", + "Subjects:": "Konular:", + "Theme Color": "Tema Rengi", + "Theme Mode": "Tema Modu", + "Unknown": "Bilinmiyor", + "Untitled": "Başlıksız", + "Updated:": "Güncellendi:", + "User avatar": "Kullanıcı avatarı", + "Version {{version}}": "Sürüm {{version}}", + "Welcome to your library. You can import your books here and read them anytime.": "Kütüphanenize hoş geldiniz. Buradan kitaplarınızı içe aktarabilir ve istediğiniz zaman okuyabilirsiniz.", + "Your Library": "Kütüphaneniz" +} diff --git a/apps/readest-app/public/locales/vi/translation.json b/apps/readest-app/public/locales/vi/translation.json new file mode 100644 index 00000000..e5504ce2 --- /dev/null +++ b/apps/readest-app/public/locales/vi/translation.json @@ -0,0 +1,92 @@ +{ + "About Readest": "Về Readest", + "Add your notes here...": "Thêm ghi chú của bạn vào đây...", + "Animation": "Hiệu ứng động", + "Auto Mode": "Chế độ tự động", + "Behavior": "Hành vi", + "Book": "Sách", + "Book Cover": "Bìa sách", + "Bookmark": "Đánh dấu", + "Cancel": "Hủy", + "Chapter": "Chương", + "Color": "Màu sắc", + "Confirm": "Xác nhận", + "Confirm Deletion": "Xác nhận xóa", + "Custom CSS": "CSS tùy chỉnh", + "Dark Mode": "Chế độ tối", + "Default Font": "Phông chữ mặc định", + "Delete": "Xóa", + "Disable Click-to-Flip": "Tắt tính năng nhấp để lật trang", + "Download Readest": "Tải Readest", + "Edit": "Chỉnh sửa", + "Excerpts": "Trích dẫn", + "Font": "Phông chữ", + "Font & Layout": "Phông chữ & Bố cục", + "Font Face": "Kiểu chữ", + "Font Family": "Họ phông chữ", + "Font Size": "Cỡ chữ", + "From Local File": "Từ tệp cục bộ", + "Full Justification": "Căn đều hai bên", + "Gaps (%)": "Khoảng cách (%)", + "Global Settings": "Cài đặt chung", + "Go Back": "Quay lại", + "Go Forward": "Tiến tới", + "Go Left": "Sang trái", + "Go Right": "Sang phải", + "Hyphenation": "Gạch nối từ", + "Identifier:": "Định danh:", + "Import Books": "Nhập sách", + "Invert Colors in Dark Mode": "Đảo màu trong chế độ tối", + "Language:": "Ngôn ngữ:", + "Layout": "Bố cục", + "Light Mode": "Chế độ sáng", + "Loading...": "Đang tải...", + "Loc. {{currentPage}} / {{totalPage}}": "Vị trí {{currentPage}} / {{totalPage}}", + "Logged in": "Đã đăng nhập", + "Logged in as {{userDisplayName}}": "Đăng nhập với tên {{userDisplayName}}", + "Margins (px)": "Lề (px)", + "Match Case": "Phân biệt chữ hoa/thường", + "Match Diacritics": "Phân biệt dấu", + "Match Whole Words": "Khớp toàn bộ từ", + "Maximum Block Size": "Kích thước khối tối đa", + "Maximum Inline Size": "Kích thước nội tuyến tối đa", + "Maximum Number of Columns": "Số cột tối đa", + "Misc": "Khác", + "Monospace Font": "Phông chữ đơn cách", + "More Info": "Thông tin thêm", + "Notebook": "Sổ ghi chép", + "Notes": "Ghi chú", + "Open": "Mở", + "Override Publisher Font": "Ghi đè phông chữ của nhà xuất bản", + "Page": "Trang", + "Paging Animation": "Hiệu ứng lật trang", + "Paragraph": "Đoạn văn", + "Parallel Read": "Đọc song song", + "Published:": "Xuất bản:", + "Publisher:": "Nhà xuất bản:", + "Reload Page": "Tải lại trang", + "Reveal in File Explorer": "Hiển thị trong File Explorer", + "Reveal in Finder": "Hiển thị trong Finder", + "Reveal in Folder": "Hiển thị trong thư mục", + "Sans-Serif Font": "Phông chữ không chân", + "Save": "Lưu", + "Scrolled Mode": "Chế độ cuộn", + "Search books...": "Tìm kiếm sách...", + "Search...": "Tìm kiếm...", + "Select books": "Chọn sách", + "Select multiple books": "Chọn nhiều sách", + "Serif Font": "Phông chữ có chân", + "Sidebar": "Thanh bên", + "Sign In": "Đăng nhập", + "Sign Out": "Đăng xuất", + "Subjects:": "Chủ đề:", + "Theme Color": "Màu chủ đề", + "Theme Mode": "Chế độ chủ đề", + "Unknown": "Không xác định", + "Untitled": "Không có tiêu đề", + "Updated:": "Cập nhật:", + "User avatar": "Ảnh đại diện", + "Version {{version}}": "Phiên bản {{version}}", + "Welcome to your library. You can import your books here and read them anytime.": "Chào mừng đến với thư viện của bạn. Bạn có thể nhập sách vào đây và đọc bất cứ lúc nào.", + "Your Library": "Thư viện của bạn" +} diff --git a/apps/readest-app/public/locales/zh-CN/translation.json b/apps/readest-app/public/locales/zh-CN/translation.json new file mode 100644 index 00000000..63f57c55 --- /dev/null +++ b/apps/readest-app/public/locales/zh-CN/translation.json @@ -0,0 +1,92 @@ +{ + "About Readest": "关于 Readest", + "Add your notes here...": "在这里添加您的笔记...", + "Animation": "动画", + "Auto Mode": "自动主题", + "Behavior": "行为", + "Book": "书籍", + "Book Cover": "书籍封面", + "Bookmark": "书签", + "Cancel": "取消", + "Chapter": "章节", + "Color": "颜色", + "Confirm": "确认", + "Confirm Deletion": "确认删除", + "Custom CSS": "自定义 CSS", + "Dark Mode": "深色主题", + "Default Font": "默认字体", + "Delete": "删除", + "Disable Click-to-Flip": "禁用点击翻页", + "Download Readest": "下载 Readest", + "Edit": "编辑", + "Excerpts": "摘录", + "Font": "字体", + "Font & Layout": "字体和布局", + "Font Face": "字型", + "Font Family": "字族", + "Font Size": "字号", + "From Local File": "从本地文件导入", + "Full Justification": "两端对齐", + "Gaps (%)": "间距 (%)", + "Global Settings": "全局设置", + "Go Back": "返回", + "Go Forward": "前进", + "Go Left": "向左", + "Go Right": "向右", + "Hyphenation": "断字", + "Identifier:": "识别码", + "Import Books": "导入书籍", + "Invert Colors in Dark Mode": "深色主题下反色", + "Language:": "语言", + "Layout": "布局", + "Light Mode": "浅色主题", + "Loading...": "加载中...", + "Loc. {{currentPage}} / {{totalPage}}": "位置 {{currentPage}} / {{totalPage}}", + "Logged in": "已登录", + "Logged in as {{userDisplayName}}": "{{userDisplayName}} 已登录", + "Margins (px)": "页边距 (px)", + "Match Case": "匹配大小写", + "Match Diacritics": "匹配重音符号", + "Match Whole Words": "匹配整个单词", + "Maximum Block Size": "内容最大宽度", + "Maximum Inline Size": "每栏最大宽度", + "Maximum Number of Columns": "分栏数", + "Misc": "杂项", + "Monospace Font": "等宽字体", + "More Info": "更多信息", + "Notebook": "笔记本", + "Notes": "笔记", + "Open": "打开", + "Override Publisher Font": "覆盖内置字体", + "Page": "页", + "Paging Animation": "翻页动画", + "Paragraph": "段落", + "Parallel Read": "并排阅读", + "Published:": "出版日期", + "Publisher:": "出版商", + "Reload Page": "重新加载页面", + "Reveal in File Explorer": "在文件管理器中显示", + "Reveal in Finder": "在访达中显示", + "Reveal in Folder": "在文件夹中显示", + "Sans-Serif Font": "无衬线字体", + "Save": "保存", + "Scrolled Mode": "滚动模式", + "Search books...": "搜索书籍...", + "Search...": "搜索...", + "Select books": "选择书籍", + "Select multiple books": "选择多本书籍", + "Serif Font": "衬线字体", + "Sidebar": "侧边栏", + "Sign In": "登录", + "Sign Out": "登出", + "Subjects:": "主题", + "Theme Color": "主题颜色", + "Theme Mode": "主题模式", + "Unknown": "未知", + "Untitled": "无标题", + "Updated:": "更新日期", + "User avatar": "用户头像", + "Version {{version}}": "版本 {{version}}", + "Welcome to your library. You can import your books here and read them anytime.": "书库空空如也,您可以导入您的书籍并随时阅读。", + "Your Library": "书库" +} diff --git a/apps/readest-app/public/locales/zh-TW/translation.json b/apps/readest-app/public/locales/zh-TW/translation.json new file mode 100644 index 00000000..28400d1a --- /dev/null +++ b/apps/readest-app/public/locales/zh-TW/translation.json @@ -0,0 +1,92 @@ +{ + "About Readest": "關於 Readest", + "Add your notes here...": "在這裡添加您的筆記...", + "Animation": "動畫", + "Auto Mode": "自動主題", + "Behavior": "行為", + "Book": "書籍", + "Book Cover": "書籍封面", + "Bookmark": "書籤", + "Cancel": "取消", + "Chapter": "章節", + "Color": "顏色", + "Confirm": "確認", + "Confirm Deletion": "確認刪除", + "Custom CSS": "自定義 CSS", + "Dark Mode": "深色主題", + "Default Font": "預設字體", + "Delete": "刪除", + "Disable Click-to-Flip": "禁用點擊翻頁", + "Download Readest": "下載 Readest", + "Edit": "編輯", + "Excerpts": "摘錄", + "Font": "字體", + "Font & Layout": "字體和版面", + "Font Face": "字型", + "Font Family": "字族", + "Font Size": "字號", + "From Local File": "從本地檔案導入", + "Full Justification": "兩端對齊", + "Gaps (%)": "間距 (%)", + "Global Settings": "全局設置", + "Go Back": "返回", + "Go Forward": "前進", + "Go Left": "向左", + "Go Right": "向右", + "Hyphenation": "斷字", + "Identifier:": "識別碼", + "Import Books": "導入書籍", + "Invert Colors in Dark Mode": "深色主題下反色", + "Language:": "語言", + "Layout": "版面", + "Light Mode": "淺色主題", + "Loading...": "載入中...", + "Loc. {{currentPage}} / {{totalPage}}": "位置 {{currentPage}} / {{totalPage}}", + "Logged in": "已登入", + "Logged in as {{userDisplayName}}": "{{userDisplayName}} 已登入", + "Margins (px)": "頁邊距 (px)", + "Match Case": "匹配大小寫", + "Match Diacritics": "匹配重音符號", + "Match Whole Words": "匹配整個單詞", + "Maximum Block Size": "內容最大寬度", + "Maximum Inline Size": "每欄最大寬度", + "Maximum Number of Columns": "分欄數", + "Misc": "雜項", + "Monospace Font": "等寬字體", + "More Info": "更多信息", + "Notebook": "筆記本", + "Notes": "筆記", + "Open": "打開", + "Override Publisher Font": "覆蓋內置字體", + "Page": "頁", + "Paging Animation": "翻頁動畫", + "Paragraph": "段落", + "Parallel Read": "並排閱讀", + "Published:": "出版日期", + "Publisher:": "出版商", + "Reload Page": "重新載入頁面", + "Reveal in File Explorer": "在檔案管理器中顯示", + "Reveal in Finder": "在訪達中顯示", + "Reveal in Folder": "在資料夾中顯示", + "Sans-Serif Font": "無襯線字體", + "Save": "保存", + "Scrolled Mode": "滾動模式", + "Search books...": "搜索書籍...", + "Search...": "搜索...", + "Select books": "選擇書籍", + "Select multiple books": "選擇多本書籍", + "Serif Font": "襯線字體", + "Sidebar": "側邊欄", + "Sign In": "登入", + "Sign Out": "登出", + "Subjects:": "主題", + "Theme Color": "主題顏色", + "Theme Mode": "主題模式", + "Unknown": "未知", + "Untitled": "無標題", + "Updated:": "更新日期", + "User avatar": "用戶頭像", + "Version {{version}}": "版本 {{version}}", + "Welcome to your library. You can import your books here and read them anytime.": "書庫空空如也,您可以導入您的書籍並隨時閱讀。", + "Your Library": "書庫" +} diff --git a/apps/readest-app/src/app/layout.tsx b/apps/readest-app/src/app/layout.tsx index 2970069e..82fb0bea 100644 --- a/apps/readest-app/src/app/layout.tsx +++ b/apps/readest-app/src/app/layout.tsx @@ -15,7 +15,7 @@ const previewImage = 'https://cdn.readest.com/images/open_graph_preview_read_now export default function RootLayout({ children }: { children: React.ReactNode }) { return ( - + {title} diff --git a/apps/readest-app/src/app/library/components/Bookshelf.tsx b/apps/readest-app/src/app/library/components/Bookshelf.tsx index 7c7552bd..5fed7a9c 100644 --- a/apps/readest-app/src/app/library/components/Bookshelf.tsx +++ b/apps/readest-app/src/app/library/components/Bookshelf.tsx @@ -4,7 +4,7 @@ import { useEffect, useRef, useState } from 'react'; import { PiPlus } from 'react-icons/pi'; import { MdDelete, MdOpenInNew } from 'react-icons/md'; import { MdCheckCircle, MdCheckCircleOutline } from 'react-icons/md'; -import { CiCircleMore } from "react-icons/ci"; +import { CiCircleMore } from 'react-icons/ci'; import { useRouter, useSearchParams } from 'next/navigation'; import Image from 'next/image'; @@ -15,6 +15,7 @@ import { Book, BooksGroup } from '@/types/book'; import { useEnv } from '@/context/EnvContext'; import { useLibraryStore } from '@/store/libraryStore'; import { useSettingsStore } from '@/store/settingsStore'; +import { useTranslation } from '@/hooks/useTranslation'; import { navigateToReader } from '@/utils/nav'; import { getOSPlatform } from '@/utils/misc'; import { getFilename } from '@/utils/book'; @@ -58,6 +59,7 @@ interface BookshelfProps { } const Bookshelf: React.FC = ({ libraryBooks, isSelectMode, onImportBooks }) => { + const _ = useTranslation(); const router = useRouter(); const searchParams = useSearchParams(); const { envConfig, appService } = useEnv(); @@ -153,14 +155,14 @@ const Bookshelf: React.FC = ({ libraryBooks, isSelectMode, onImp const fileRevealLabel = FILE_REVEAL_LABELS[osPlatform as FILE_REVEAL_PLATFORMS] || FILE_REVEAL_LABELS.default; const showBookInFinderMenuItem = await MenuItem.new({ - text: fileRevealLabel, + text: _(fileRevealLabel), action: async () => { const folder = `${settings.localBooksDir}/${getFilename(book)}`; revealItemInDir(folder); }, }); const deleteBookMenuItem = await MenuItem.new({ - text: 'Delete', + text: _('Delete'), action: async () => { deleteBook(envConfig, book); }, @@ -185,7 +187,8 @@ const Bookshelf: React.FC = ({ libraryBooks, isSelectMode, onImp className='book-item cursor-pointer' onContextMenu={bookContextMenuHandler.bind(null, item as Book)} > -
handleBookClick(item.hash)} > @@ -276,11 +279,11 @@ const Bookshelf: React.FC = ({ libraryBooks, isSelectMode, onImp
)} @@ -291,16 +294,15 @@ const Bookshelf: React.FC = ({ libraryBooks, isSelectMode, onImp )} {showDeleteAlert && ( setShowDeleteAlert(false)} onClickConfirm={confirmDelete} /> )} - - {/* Modal Component */} + {selectedBook && ( - + )}
); diff --git a/apps/readest-app/src/app/library/components/LibraryHeader.tsx b/apps/readest-app/src/app/library/components/LibraryHeader.tsx index af30cbd1..56007c22 100644 --- a/apps/readest-app/src/app/library/components/LibraryHeader.tsx +++ b/apps/readest-app/src/app/library/components/LibraryHeader.tsx @@ -3,12 +3,13 @@ import React, { useEffect, useRef } from 'react'; import { FaSearch } from 'react-icons/fa'; import { PiPlus } from 'react-icons/pi'; import { PiSelectionAllDuotone } from 'react-icons/pi'; +import { MdOutlineMenu } from 'react-icons/md'; import { useEnv } from '@/context/EnvContext'; +import { useTranslation } from '@/hooks/useTranslation'; import useTrafficLight from '@/hooks/useTrafficLight'; import WindowButtons from '@/components/WindowButtons'; import Dropdown from '@/components/Dropdown'; -import { MdOutlineMenu } from 'react-icons/md'; import SettingsMenu from './SettingsMenu'; interface LibraryHeaderProps { @@ -22,6 +23,7 @@ const LibraryHeader: React.FC = ({ onImportBooks, onToggleSelectMode, }) => { + const _ = useTranslation(); const { appService } = useEnv(); const { isTrafficLightVisible } = useTrafficLight(); const headerRef = useRef(null); @@ -53,7 +55,7 @@ const LibraryHeader: React.FC = ({ = ({ >
  • - diff --git a/apps/readest-app/src/app/reader/components/BookmarkToggler.tsx b/apps/readest-app/src/app/reader/components/BookmarkToggler.tsx index 43ee2515..9634e61c 100644 --- a/apps/readest-app/src/app/reader/components/BookmarkToggler.tsx +++ b/apps/readest-app/src/app/reader/components/BookmarkToggler.tsx @@ -5,6 +5,7 @@ import * as CFI from 'foliate-js/epubcfi.js'; import { useSettingsStore } from '@/store/settingsStore'; import { useBookDataStore } from '@/store/bookDataStore'; import { useReaderStore } from '@/store/readerStore'; +import { useTranslation } from '@/hooks/useTranslation'; import { useEnv } from '@/context/EnvContext'; import { BookNote } from '@/types/book'; import { uniqueId } from '@/utils/misc'; @@ -15,6 +16,7 @@ interface BookmarkTogglerProps { } const BookmarkToggler: React.FC = ({ bookKey }) => { + const _ = useTranslation(); const { envConfig } = useEnv(); const { settings } = useSettingsStore(); const { getConfig, saveConfig, updateBooknotes } = useBookDataStore(); @@ -98,7 +100,7 @@ const BookmarkToggler: React.FC = ({ bookKey }) => { ) } onClick={toggleBookmark} - tooltip='Bookmark' + tooltip={_('Bookmark')} tooltipDirection='bottom' > ); diff --git a/apps/readest-app/src/app/reader/components/FooterBar.tsx b/apps/readest-app/src/app/reader/components/FooterBar.tsx index 226b0104..5052487b 100644 --- a/apps/readest-app/src/app/reader/components/FooterBar.tsx +++ b/apps/readest-app/src/app/reader/components/FooterBar.tsx @@ -5,6 +5,7 @@ import { RiArrowGoBackLine, RiArrowGoForwardLine } from 'react-icons/ri'; import { useReaderStore } from '@/store/readerStore'; import { useSidebarStore } from '@/store/sidebarStore'; +import { useTranslation } from '@/hooks/useTranslation'; import Button from '@/components/Button'; interface FooterBarProps { @@ -14,6 +15,7 @@ interface FooterBarProps { } const FooterBar: React.FC = ({ bookKey, pageinfo, isHoveredAnim }) => { + const _ = useTranslation(); const { hoveredBookKey, setHoveredBookKey, getView } = useReaderStore(); const { isSideBarVisible } = useSidebarStore(); const view = getView(bookKey); @@ -53,17 +55,21 @@ const FooterBar: React.FC = ({ bookKey, pageinfo, isHoveredAnim onMouseEnter={() => setHoveredBookKey(bookKey)} onMouseLeave={() => setHoveredBookKey('')} > - ); diff --git a/apps/readest-app/src/app/reader/components/PageInfo.tsx b/apps/readest-app/src/app/reader/components/PageInfo.tsx index 74d21160..59dd5d28 100644 --- a/apps/readest-app/src/app/reader/components/PageInfo.tsx +++ b/apps/readest-app/src/app/reader/components/PageInfo.tsx @@ -1,5 +1,6 @@ -import { PageInfo } from '@/types/book'; import React from 'react'; +import { useTranslation } from '@/hooks/useTranslation'; +import { PageInfo } from '@/types/book'; interface PageInfoProps { bookFormat: string; @@ -9,13 +10,17 @@ interface PageInfoProps { } const PageInfoView: React.FC = ({ bookFormat, section, pageinfo, gapRight }) => { + const _ = useTranslation(); const pageInfo = bookFormat === 'PDF' ? section ? `${section.current + 1} / ${section.total}` : '' : pageinfo - ? `Loc. ${pageinfo.current + 1} / ${pageinfo.total}` + ? _('Loc. {{currentPage}} / {{totalPage}}', { + currentPage: pageinfo.current + 1, + totalPage: pageinfo.total, + }) : ''; return ( diff --git a/apps/readest-app/src/app/reader/components/SidebarToggler.tsx b/apps/readest-app/src/app/reader/components/SidebarToggler.tsx index ff416228..7ad73970 100644 --- a/apps/readest-app/src/app/reader/components/SidebarToggler.tsx +++ b/apps/readest-app/src/app/reader/components/SidebarToggler.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { TbLayoutSidebar, TbLayoutSidebarFilled } from 'react-icons/tb'; import { useSidebarStore } from '@/store/sidebarStore'; +import { useTranslation } from '@/hooks/useTranslation'; import Button from '@/components/Button'; interface SidebarTogglerProps { @@ -9,6 +10,7 @@ interface SidebarTogglerProps { } const SidebarToggler: React.FC = ({ bookKey }) => { + const _ = useTranslation(); const { sideBarBookKey, isSideBarVisible, setSideBarBookKey, toggleSideBar } = useSidebarStore(); const handleToggleSidebar = () => { if (sideBarBookKey === bookKey) { @@ -28,7 +30,7 @@ const SidebarToggler: React.FC = ({ bookKey }) => { ) } onClick={handleToggleSidebar} - tooltip='Sidebar' + tooltip={_('Sidebar')} tooltipDirection='bottom' /> ); diff --git a/apps/readest-app/src/app/reader/components/ViewMenu.tsx b/apps/readest-app/src/app/reader/components/ViewMenu.tsx index 51222647..ba5a2f82 100644 --- a/apps/readest-app/src/app/reader/components/ViewMenu.tsx +++ b/apps/readest-app/src/app/reader/components/ViewMenu.tsx @@ -8,6 +8,7 @@ import { MdZoomOut, MdZoomIn, MdCheck } from 'react-icons/md'; import { ONE_COLUMN_MAX_INLINE_SIZE } from '@/services/constants'; import MenuItem from '@/components/MenuItem'; import { useReaderStore } from '@/store/readerStore'; +import { useTranslation } from '@/hooks/useTranslation'; import { useTheme, ThemeMode } from '@/hooks/useTheme'; import { getStyles } from '@/utils/style'; @@ -22,6 +23,7 @@ const ViewMenu: React.FC = ({ setIsDropdownOpen, onSetSettingsDialogOpen, }) => { + const _ = useTranslation(); const { getView, getViews, getViewSettings, setViewSettings } = useReaderStore(); const viewSettings = getViewSettings(bookKey)!; @@ -126,10 +128,10 @@ const ViewMenu: React.FC = ({
    - + : undefined} onClick={toggleScrolledMode} @@ -139,7 +141,11 @@ const ViewMenu: React.FC = ({ = ({ onClick={cycleThemeMode} /> : undefined} onClick={toggleInvertedColors} disabled={!isDarkMode} diff --git a/apps/readest-app/src/app/reader/components/notebook/Header.tsx b/apps/readest-app/src/app/reader/components/notebook/Header.tsx index dda5eac3..910caf86 100644 --- a/apps/readest-app/src/app/reader/components/notebook/Header.tsx +++ b/apps/readest-app/src/app/reader/components/notebook/Header.tsx @@ -2,27 +2,31 @@ import React from 'react'; import { FiSearch } from 'react-icons/fi'; import { MdOutlinePushPin, MdPushPin } from 'react-icons/md'; +import { useTranslation } from '@/hooks/useTranslation'; const NotebookHeader: React.FC<{ isPinned: boolean; handleTogglePin: () => void; -}> = ({ isPinned, handleTogglePin }) => ( -
    -
    -
    Notebook
    +}> = ({ isPinned, handleTogglePin }) => { + const _ = useTranslation(); + return ( +
    +
    +
    {_('Notebook')}
    +
    +
    + + +
    -
    - - -
    -
    -); + ); +}; export default NotebookHeader; diff --git a/apps/readest-app/src/app/reader/components/notebook/NoteEditor.tsx b/apps/readest-app/src/app/reader/components/notebook/NoteEditor.tsx index 44929753..bf4fbf1b 100644 --- a/apps/readest-app/src/app/reader/components/notebook/NoteEditor.tsx +++ b/apps/readest-app/src/app/reader/components/notebook/NoteEditor.tsx @@ -1,6 +1,7 @@ import clsx from 'clsx'; import React, { useEffect, useRef } from 'react'; import { useNotebookStore } from '@/store/notebookStore'; +import { useTranslation } from '@/hooks/useTranslation'; import { TextSelection } from '@/utils/sel'; import { BookNote } from '@/types/book'; @@ -10,6 +11,7 @@ interface NoteEditorProps { } const NoteEditor: React.FC = ({ onSave, onEdit }) => { + const _ = useTranslation(); const { notebookNewAnnotation, notebookEditAnnotation } = useNotebookStore(); const editorRef = useRef(null); const [note, setNote] = React.useState(''); @@ -62,7 +64,7 @@ const NoteEditor: React.FC = ({ onSave, onEdit }) => { rows={1} spellCheck={false} onChange={handleChange} - placeholder='Add your notes here...' + placeholder={_('Add your notes here...')} >
    diff --git a/apps/readest-app/src/app/reader/components/notebook/Notebook.tsx b/apps/readest-app/src/app/reader/components/notebook/Notebook.tsx index 83f57cde..c4fcf755 100644 --- a/apps/readest-app/src/app/reader/components/notebook/Notebook.tsx +++ b/apps/readest-app/src/app/reader/components/notebook/Notebook.tsx @@ -6,6 +6,7 @@ import { useBookDataStore } from '@/store/bookDataStore'; import { useReaderStore } from '@/store/readerStore'; import { useSidebarStore } from '@/store/sidebarStore'; import { useNotebookStore } from '@/store/notebookStore'; +import { useTranslation } from '@/hooks/useTranslation'; import { useEnv } from '@/context/EnvContext'; import useDragBar from '../../hooks/useDragBar'; import NotebookHeader from './Header'; @@ -19,6 +20,7 @@ const MIN_NOTEBOOK_WIDTH = 0.15; const MAX_NOTEBOOK_WIDTH = 0.45; const Notebook: React.FC = ({}) => { + const _ = useTranslation(); const { envConfig } = useEnv(); const { settings } = useSettingsStore(); const { sideBarBookKey } = useSidebarStore(); @@ -139,7 +141,7 @@ const Notebook: React.FC = ({}) => { />
    -
    {excerptNotes.length > 0 &&

    Excerpts

    }
    +
    {excerptNotes.length > 0 &&

    {_('Excerpts')}

    }
      {excerptNotes.map((item, index) => (
    • @@ -171,7 +173,7 @@ const Notebook: React.FC = ({}) => { )} onClick={handleEditNote.bind(null, item, true)} > -
      Delete
      +
      {_('Delete')}
    @@ -181,7 +183,7 @@ const Notebook: React.FC = ({}) => {
    {(notebookNewAnnotation || annotationNotes.length > 0) && ( -

    Notes

    +

    {_('Notes')}

    )}
    {(notebookNewAnnotation || notebookEditAnnotation) && ( diff --git a/apps/readest-app/src/app/reader/components/settings/ColorPanel.tsx b/apps/readest-app/src/app/reader/components/settings/ColorPanel.tsx index 80a76d3b..3f92b516 100644 --- a/apps/readest-app/src/app/reader/components/settings/ColorPanel.tsx +++ b/apps/readest-app/src/app/reader/components/settings/ColorPanel.tsx @@ -6,9 +6,11 @@ import { TbSunMoon } from 'react-icons/tb'; import { useTheme } from '@/hooks/useTheme'; import { themes } from '@/styles/themes'; import { useReaderStore } from '@/store/readerStore'; +import { useTranslation } from '@/hooks/useTranslation'; import { getStyles } from '@/utils/style'; const ColorPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { + const _ = useTranslation(); const { themeMode, themeColor, themeCode, isDarkMode, updateThemeMode, updateThemeColor } = useTheme(); const { getViews, getViewSettings } = useReaderStore(); @@ -24,9 +26,9 @@ const ColorPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { return (
    -

    Theme Mode

    +

    {_('Theme Mode')}

    -
    +
    -
    +
    -
    +
    -

    Theme Color

    +

    {_('Theme Color')}

    {themes.map(({ name, label, colors }) => (
    diff --git a/apps/readest-app/src/app/reader/components/settings/FontPanel.tsx b/apps/readest-app/src/app/reader/components/settings/FontPanel.tsx index e36572e4..02ddec25 100644 --- a/apps/readest-app/src/app/reader/components/settings/FontPanel.tsx +++ b/apps/readest-app/src/app/reader/components/settings/FontPanel.tsx @@ -6,8 +6,9 @@ import FontDropdown from './FontDropDown'; import { MONOSPACE_FONTS, SANS_SERIF_FONTS, SERIF_FONTS } from '@/services/constants'; import { useReaderStore } from '@/store/readerStore'; import { useSettingsStore } from '@/store/settingsStore'; -import { getStyles } from '@/utils/style'; +import { useTranslation } from '@/hooks/useTranslation'; import { useTheme } from '@/hooks/useTheme'; +import { getStyles } from '@/utils/style'; interface FontFaceProps { className?: string; @@ -38,6 +39,7 @@ const FontFace = ({ className, family, label, options, selected, onSelect }: Fon ); const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { + const _ = useTranslation(); const { settings, isFontLayoutSettingsGlobal, setSettings } = useSettingsStore(); const { getView, getViewSettings, setViewSettings } = useReaderStore(); const view = getView(bookKey); @@ -145,7 +147,7 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { return (
    -

    Font Size

    +

    {_('Font Size')}

    = ({ bookKey }) => {
    -

    Font Family

    +

    {_('Font Family')}

    - Default Font + {_('Default Font')} = ({ bookKey }) => {
    - Override Publisher Font + {_('Override Publisher Font')} = ({ bookKey }) => {
    -

    Font Face

    +

    {_('Font Face')}

    = ({ bookKey }) => { = ({ bookKey }) => { + const _ = useTranslation(); const { settings, isFontLayoutSettingsGlobal, setSettings } = useSettingsStore(); const { getView, getViewSettings, setViewSettings } = useReaderStore(); const view = getView(bookKey); @@ -112,7 +114,7 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { return (
    -

    Paragraph

    +

    {_('Paragraph')}

    = ({ bookKey }) => { step={0.1} />
    - Full Justification + {_('Full Justification')} = ({ bookKey }) => { />
    - Hyphenation + {_('Hyphenation')} = ({ bookKey }) => {
    -

    Page

    +

    {_('Page')}

    = ({ bookKey }) => { step={4} /> = ({ bookKey }) => { step={100} /> +~$$$$\"=(),*\s]+)\s*{(?:[\s]*)((?:[^\}]+[:][^\}]+;?)*)*\s*}(?:\s*))/gim; const MiscPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { + const _ = useTranslation(); const { settings, isFontLayoutSettingsGlobal, setSettings } = useSettingsStore(); const { getView, getViewSettings, setViewSettings } = useReaderStore(); const viewSettings = getViewSettings(bookKey)!; @@ -87,11 +89,11 @@ const MiscPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { return (
    -

    Animation

    +

    {_('Animation')}

    - Paging Animation + {_('Paging Animation')} = ({ bookKey }) => {
    -

    Behavior

    +

    {_('Behavior')}

    - Disable Click-to-Flip + {_('Disable Click-to-Flip')} = ({ bookKey }) => {
    -

    Custom CSS

    +

    {_('Custom CSS')}

    diff --git a/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx b/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx index e4f73c46..cc8c89bc 100644 --- a/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx +++ b/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useState } from 'react'; import { BookConfig } from '@/types/book'; import { useSettingsStore } from '@/store/settingsStore'; +import { useTranslation } from '@/hooks/useTranslation'; import { RiFontSize } from 'react-icons/ri'; import { RiDashboardLine } from 'react-icons/ri'; import { VscSymbolColor } from 'react-icons/vsc'; @@ -15,8 +16,11 @@ import Dropdown from '@/components/Dropdown'; import DialogMenu from './DialogMenu'; import MiscPanel from './MiscPanel'; +type SettingsPanelType = 'Font' | 'Layout' | 'Color' | 'Misc'; + const SettingsDialog: React.FC<{ bookKey: string; config: BookConfig }> = ({ bookKey }) => { - const [activePanel, setActivePanel] = useState('Font'); + const _ = useTranslation(); + const [activePanel, setActivePanel] = useState('Font'); const { setFontLayoutSettingsDialogOpen } = useSettingsStore(); const handleKeyDown = (event: KeyboardEvent) => { @@ -43,28 +47,28 @@ const SettingsDialog: React.FC<{ bookKey: string; config: BookConfig }> = ({ boo onClick={() => setActivePanel('Font')} > - Font + {_('Font')}
    diff --git a/apps/readest-app/src/app/reader/components/sidebar/BookCard.tsx b/apps/readest-app/src/app/reader/components/sidebar/BookCard.tsx index 79aca486..edf134c4 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/BookCard.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/BookCard.tsx @@ -1,6 +1,7 @@ import React from 'react'; import Image from 'next/image'; import { MdInfoOutline } from 'react-icons/md'; +import { useTranslation } from '@/hooks/useTranslation'; interface BookCardProps { cover: string; @@ -9,11 +10,12 @@ interface BookCardProps { } const BookCard: React.FC = ({ cover, title, author }) => { + const _ = useTranslation(); return (
    Book cover = ({ cover, title, author }) => {
    diff --git a/apps/readest-app/src/app/reader/components/sidebar/BookMenu.tsx b/apps/readest-app/src/app/reader/components/sidebar/BookMenu.tsx index b26de7b2..7e2defa0 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/BookMenu.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/BookMenu.tsx @@ -4,6 +4,7 @@ import Image from 'next/image'; import MenuItem from '@/components/MenuItem'; import { setAboutDialogVisible } from '@/components/AboutWindow'; import { useLibraryStore } from '@/store/libraryStore'; +import { useTranslation } from '@/hooks/useTranslation'; import { isWebAppPlatform } from '@/services/environment'; import { DOWNLOAD_READEST_URL } from '@/services/constants'; import useBooksManager from '../../hooks/useBooksManager'; @@ -13,6 +14,7 @@ interface BookMenuProps { } const BookMenu: React.FC = ({ setIsDropdownOpen }) => { + const _ = useTranslation(); const { library } = useLibraryStore(); const { openParallelView } = useBooksManager(); const handleParallelView = (id: string) => { @@ -39,7 +41,7 @@ const BookMenu: React.FC = ({ setIsDropdownOpen }) => { tabIndex={0} className='book-menu dropdown-content dropdown-center border-base-100 z-20 mt-3 w-60 shadow-2xl' > - +
      {library.slice(0, 20).map((book) => ( = ({ setIsDropdownOpen }) => { ))}
    - +
    {isWebApp && } - +
    ); }; diff --git a/apps/readest-app/src/app/reader/components/sidebar/BooknoteItem.tsx b/apps/readest-app/src/app/reader/components/sidebar/BooknoteItem.tsx index ee4f22e8..4c9935fb 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/BooknoteItem.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/BooknoteItem.tsx @@ -6,8 +6,9 @@ import { BookNote } from '@/types/book'; import { useSettingsStore } from '@/store/settingsStore'; import { useReaderStore } from '@/store/readerStore'; import { useNotebookStore } from '@/store/notebookStore'; -import useScrollToItem from '../../hooks/useScrollToItem'; import { useBookDataStore } from '@/store/bookDataStore'; +import { useTranslation } from '@/hooks/useTranslation'; +import useScrollToItem from '../../hooks/useScrollToItem'; interface BooknoteItemProps { bookKey: string; @@ -16,6 +17,7 @@ interface BooknoteItemProps { } const BooknoteItem: React.FC = ({ bookKey, item, editable = false }) => { + const _ = useTranslation(); const { envConfig } = useEnv(); const { settings } = useSettingsStore(); const { getConfig, saveConfig, updateBooknotes } = useBookDataStore(); @@ -115,7 +117,7 @@ const BooknoteItem: React.FC = ({ bookKey, item, editable = f )} onClick={editNote.bind(null, item)} > -
    Edit
    +
    {_('Edit')}
    )}
    diff --git a/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx b/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx index b45b1625..97222e3d 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx @@ -5,6 +5,7 @@ import { useEnv } from '@/context/EnvContext'; import { useSettingsStore } from '@/store/settingsStore'; import { useBookDataStore } from '@/store/bookDataStore'; import { useReaderStore } from '@/store/readerStore'; +import { useTranslation } from '@/hooks/useTranslation'; import { BookSearchConfig, BookSearchResult } from '@/types/book'; import Dropdown from '@/components/Dropdown'; import SearchOptions from './SearchOptions'; @@ -24,6 +25,7 @@ const SearchBar: React.FC = ({ searchTerm: term, onSearchResultChange, }) => { + const _ = useTranslation(); const { envConfig } = useEnv(); const { settings } = useSettingsStore(); const { getConfig, saveConfig } = useBookDataStore(); @@ -149,7 +151,7 @@ const SearchBar: React.FC = ({ value={searchTerm} spellCheck={false} onChange={handleInputChange} - placeholder='Search...' + placeholder={_('Search...')} className='w-full bg-transparent p-2 font-sans text-sm font-light focus:outline-none' /> diff --git a/apps/readest-app/src/app/reader/components/sidebar/SearchOptions.tsx b/apps/readest-app/src/app/reader/components/sidebar/SearchOptions.tsx index de6f084b..9f9e0b2a 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/SearchOptions.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/SearchOptions.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { MdCheck } from 'react-icons/md'; import { BookSearchConfig } from '@/types/book'; +import { useTranslation } from '@/hooks/useTranslation'; interface SearchOptionsProps { searchConfig: BookSearchConfig; @@ -13,6 +14,7 @@ const SearchOptions: React.FC = ({ onSearchConfigChanged, setIsDropdownOpen, }) => { + const _ = useTranslation(); const handleSetScope = () => { onSearchConfigChanged({ ...searchConfig, @@ -46,7 +48,7 @@ const SearchOptions: React.FC = ({ {searchConfig.scope === 'book' && } - Book + {_('Book')}
    @@ -60,7 +62,7 @@ const SearchOptions: React.FC = ({ )} - Chapter + {_('Chapter')}
    @@ -74,7 +76,7 @@ const SearchOptions: React.FC = ({ {searchConfig.matchCase && } - Match Case + {_('Match Case')}
    @@ -86,7 +88,7 @@ const SearchOptions: React.FC = ({ {searchConfig.matchWholeWords && } - Match Whole Words + {_('Match Whole Words')}
    @@ -98,7 +100,7 @@ const SearchOptions: React.FC = ({ {searchConfig.matchDiacritics && } - Match Diacritics + {_('Match Diacritics')}
    diff --git a/apps/readest-app/src/components/AboutWindow.tsx b/apps/readest-app/src/components/AboutWindow.tsx index aee56d86..a8440140 100644 --- a/apps/readest-app/src/components/AboutWindow.tsx +++ b/apps/readest-app/src/components/AboutWindow.tsx @@ -2,6 +2,7 @@ import React from 'react'; import Image from 'next/image'; import packageJson from '../../package.json'; import WindowButtons from './WindowButtons'; +import { useTranslation } from '@/hooks/useTranslation'; export const setAboutDialogVisible = (visible: boolean) => { const dialog = document.getElementById('about_window'); @@ -13,6 +14,7 @@ export const setAboutDialogVisible = (visible: boolean) => { }; export const AboutWindow = () => { + const _ = useTranslation(); return (
    @@ -30,7 +32,9 @@ export const AboutWindow = () => {

    Readest

    Bilingify LLC

    - Version {packageJson.version} + + {_('Version {{version}}', { version: packageJson.version })} +
    @@ -55,7 +59,7 @@ export const AboutWindow = () => {

    Source code is available at{' '} void; onClickConfirm: () => void; }> = ({ title, message, onClickCancel, onClickConfirm }) => { + const _ = useTranslation(); return (

    diff --git a/apps/readest-app/src/components/Spinner.tsx b/apps/readest-app/src/components/Spinner.tsx index 2475da61..c8a0cd65 100644 --- a/apps/readest-app/src/components/Spinner.tsx +++ b/apps/readest-app/src/components/Spinner.tsx @@ -1,8 +1,10 @@ import React from 'react'; +import { useTranslation } from '@/hooks/useTranslation'; const Spinner: React.FC<{ loading: boolean; }> = ({ loading }) => { + const _ = useTranslation(); if (!loading) return null; return ( @@ -11,7 +13,7 @@ const Spinner: React.FC<{ role='status' > - Loading... + {_('Loading...')}
    ); }; diff --git a/apps/readest-app/src/hooks/useTranslation.ts b/apps/readest-app/src/hooks/useTranslation.ts new file mode 100644 index 00000000..cfc6ddd9 --- /dev/null +++ b/apps/readest-app/src/hooks/useTranslation.ts @@ -0,0 +1,12 @@ +import '@/i18n/i18n'; +import { useTranslation as _useTranslation } from 'react-i18next'; + +export const useTranslation = (namespace: string = 'translation') => { + const { t } = _useTranslation(namespace); + + return (key: string, options = {}) => t(key, { defaultValue: key, ...options }); +}; + +export const stubTranslation = (key: string) => { + return key; +}; diff --git a/apps/readest-app/src/i18n/i18n.ts b/apps/readest-app/src/i18n/i18n.ts new file mode 100644 index 00000000..6f9e2612 --- /dev/null +++ b/apps/readest-app/src/i18n/i18n.ts @@ -0,0 +1,45 @@ +import i18n from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import HttpApi from 'i18next-http-backend'; +import LanguageDetector from 'i18next-browser-languagedetector'; +import { options } from '../../i18next-scanner.config'; + +i18n + .use(HttpApi) + .use(LanguageDetector) + .use(initReactI18next) + .init({ + supportedLngs: ['en', ...options.lngs], + fallbackLng: { + 'zh-TW': ['zh-CN', 'en'], + 'de-CH': ['fr', 'it', 'en'], + zh: ['zh-CN', 'zh-TW', 'en'], + es: ['pt', 'it', 'fr', 'en'], + pt: ['es', 'it', 'fr', 'en'], + fr: ['es', 'it', 'pt', 'en'], + it: ['es', 'fr', 'pt', 'en'], + }, + ns: options.ns, + defaultNS: options.defaultNs, + backend: { + loadPath: '/locales/{{lng}}/{{ns}}.json', + }, + detection: { + order: ['querystring', 'localStorage', 'navigator'], + caches: ['localStorage'], + }, + keySeparator: false, + nsSeparator: false, + interpolation: { + escapeValue: false, + }, + react: { + useSuspense: false, + }, + }); + +i18n.on('languageChanged', (lng) => { + console.log('Language changed to', lng); +}); + +export default i18n; diff --git a/apps/readest-app/src/utils/book.ts b/apps/readest-app/src/utils/book.ts index 4ec4d401..a445713c 100644 --- a/apps/readest-app/src/utils/book.ts +++ b/apps/readest-app/src/utils/book.ts @@ -80,3 +80,21 @@ export const formatAuthors = ( export const formatTitle = (title: string | LanguageMap) => { return typeof title === 'string' ? title : formatLanguageMap(title); }; + +export const formatDate = (date: string | number | Date | undefined) => { + if (!date) return; + try { + return new Date(date).toLocaleDateString(userLang, { + year: 'numeric', + month: 'long', + day: 'numeric', + }); + } catch { + return; + } +}; + +export const formatSubject = (subject: string | string[] | undefined) => { + if (!subject) return ''; + return Array.isArray(subject) ? subject.join(', ') : subject; +}; diff --git a/apps/readest-app/src/utils/os.ts b/apps/readest-app/src/utils/os.ts index 77ca8d4c..cae12990 100644 --- a/apps/readest-app/src/utils/os.ts +++ b/apps/readest-app/src/utils/os.ts @@ -1,8 +1,10 @@ +import { stubTranslation as _ } from '@/hooks/useTranslation'; + export const FILE_REVEAL_LABELS = { - macos: 'Reveal in Finder', - windows: 'Reveal in File Explorer', - linux: 'Reveal in Folder', - default: 'Reveal in Folder', + macos: _('Reveal in Finder'), + windows: _('Reveal in File Explorer'), + linux: _('Reveal in Folder'), + default: _('Reveal in Folder'), }; export type FILE_REVEAL_PLATFORMS = keyof typeof FILE_REVEAL_LABELS; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fe09a2ed..ad5470c1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -92,6 +92,15 @@ importers: foliate-js: specifier: workspace:* version: link:../../packages/foliate-js + i18next: + specifier: ^24.2.0 + version: 24.2.0(typescript@5.7.2) + i18next-browser-languagedetector: + specifier: ^8.0.2 + version: 8.0.2 + i18next-http-backend: + specifier: ^3.0.1 + version: 3.0.1 js-md5: specifier: ^0.8.3 version: 0.8.3 @@ -107,6 +116,9 @@ importers: react-dom: specifier: 19.0.0 version: 19.0.0(react@19.0.0) + react-i18next: + specifier: ^15.2.0 + version: 15.2.0(i18next@24.2.0(typescript@5.7.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) react-icons: specifier: ^5.3.0 version: 5.3.0(react@19.0.0) @@ -156,6 +168,9 @@ importers: eslint-config-next: specifier: 15.0.3 version: 15.0.3(eslint@9.16.0(jiti@1.21.6))(typescript@5.7.2) + i18next-scanner: + specifier: ^4.6.0 + version: 4.6.0(typescript@5.7.2) mkdirp: specifier: ^3.0.1 version: 3.0.1 @@ -221,6 +236,10 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@babel/runtime@7.26.0': + resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} + engines: {node: '>=6.9.0'} + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -265,6 +284,10 @@ packages: '@fabianlars/tauri-plugin-oauth@2.0.0': resolution: {integrity: sha512-I1s08ZXrsFuYfNWusAcpLyiCfr5TCvaBrRuKfTG+XQrcaqnAcwjdWH0U5J9QWuMDLwCUMnVxdobtMJzPR8raxQ==} + '@gulpjs/to-absolute-glob@4.0.0': + resolution: {integrity: sha512-kjotm7XJrJ6v+7knhPaRgaT6q8F8K2jiafwYdNHLzmV0uGLuZY43FK6smNSHUPrhq5kX2slCUy+RGG/xGqmIKA==} + engines: {node: '>=10.13.0'} + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -983,11 +1006,41 @@ packages: resolution: {integrity: sha512-G6Bl5wN9EXXVaTUIox71vIX5Z454zEBe+akKpV4m1tUboIctT5h7ID3QXCJd/Lfy2rSvmkTmZIucf1jGRR4f5A==} engines: {bun: '>=0.7.0', deno: '>=1.0.0', node: '>=16.5.0'} + acorn-class-fields@0.3.7: + resolution: {integrity: sha512-jdUWSFce0fuADUljmExz4TWpPkxmRW/ZCPRqeeUzbGf0vFUcpQYbyq52l75qGd0oSwwtAepeL6hgb/naRgvcKQ==} + engines: {node: '>=4.8.2'} + peerDependencies: + acorn: ^6 || ^7 || ^8 + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn-private-class-elements@0.2.7: + resolution: {integrity: sha512-+GZH2wOKNZOBI4OOPmzpo4cs6mW297sn6fgIk1dUI08jGjhAaEwvC39mN2gJAg2lmAQJ1rBkFqKWonL3Zz6PVA==} + engines: {node: '>=4.8.2'} + peerDependencies: + acorn: ^6.1.0 || ^7 || ^8 + + acorn-private-methods@0.3.3: + resolution: {integrity: sha512-46oeEol3YFvLSah5m9hGMlNpxDBCEkdceJgf01AjqKYTK9r6HexKs2rgSbLK81pYjZZMonhftuUReGMlbbv05w==} + engines: {node: '>=4.8.2'} + peerDependencies: + acorn: ^6 || ^7 || ^8 + + acorn-stage3@4.0.0: + resolution: {integrity: sha512-BR+LaADtA6GTB5prkNqWmlmCLYmkyW0whvSxdHhbupTaro2qBJ95fJDEiRLPUmiACGHPaYyeH9xmNJWdGfXRQw==} + engines: {node: '>=4.8.2'} + peerDependencies: + acorn: ^7.4 || ^8 + + acorn-static-class-features@0.2.4: + resolution: {integrity: sha512-5X4mpYq5J3pdndLmIB0+WtFd/mKWnNYpuTlTzj32wUu/PMmEGOiayQ5UrqgwdBNiaZBtDDh5kddpP7Yg2QaQYA==} + engines: {node: '>=4.8.2'} + peerDependencies: + acorn: ^6.1.0 || ^7 || ^8 + acorn-walk@8.3.4: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} @@ -1095,9 +1148,15 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} + b4a@1.6.7: + resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + bare-events@2.5.0: + resolution: {integrity: sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -1111,6 +1170,9 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + bl@5.1.0: + resolution: {integrity: sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -1132,6 +1194,9 @@ packages: buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} @@ -1184,6 +1249,17 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + clone-deep@4.0.1: + resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} + engines: {node: '>=6'} + + clone-stats@1.0.0: + resolution: {integrity: sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==} + + clone@2.1.2: + resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} + engines: {node: '>=0.8'} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -1209,6 +1285,10 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + common-tags@1.8.2: resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} engines: {node: '>=4.0.0'} @@ -1219,9 +1299,15 @@ packages: construct-style-sheets-polyfill@3.1.0: resolution: {integrity: sha512-HBLKP0chz8BAY6rBdzda11c3wAZeCZ+kIG4weVC2NM3AXzxx09nhe8t0SQNdloAvg5GLuHwq/0SPOOSPvtCcKw==} + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + core-js@3.39.0: resolution: {integrity: sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==} + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cors@2.8.5: resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} engines: {node: '>= 0.10'} @@ -1234,6 +1320,9 @@ packages: create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + cross-fetch@4.0.0: + resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -1392,6 +1481,12 @@ packages: resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} engines: {node: '>=10.13.0'} + ensure-type@1.5.1: + resolution: {integrity: sha512-Dxe+mVF4MupV6eueWiFa6hUd9OL9lIM2/LqR40k1P+dwG+G2il2UigXTU9aQlaw+Y/N0BKSaTofNw73htTbC5g==} + + eol@0.9.1: + resolution: {integrity: sha512-Ds/TEoZjwggRoz/Q2O7SE3i4Jm66mqTDfmdHdq/7DKVk3bro9Q8h6WdXKdPqFLMoqxrDK5SVRzHVPOS6uuGtrg==} + es-abstract@1.23.5: resolution: {integrity: sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==} engines: {node: '>= 0.4'} @@ -1544,6 +1639,11 @@ packages: resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + esprima-next@5.8.4: + resolution: {integrity: sha512-8nYVZ4ioIH4Msjb/XmhnBdz5WRRBaYqevKa1cv9nGJdCehMbzZCPNEEnqfLCZVetUVrUPEcb5IYyu1GG4hFqgg==} + engines: {node: '>=12'} + hasBin: true + esquery@1.6.0: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} @@ -1578,6 +1678,9 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + fast-glob@3.3.1: resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} engines: {node: '>=8.6.0'} @@ -1647,6 +1750,10 @@ packages: resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} engines: {node: '>=14.14'} + fs-mkdirp-stream@2.0.1: + resolution: {integrity: sha512-UTOY+59K6IA94tec8Wjqm0FSh5OVudGNB0NL/P6fB3HiE3bYOY3VYBGijsnOHNkQSwC1FKkU77pmq7xp9CskLw==} + engines: {node: '>=10.13.0'} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1692,6 +1799,10 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + glob-stream@8.0.2: + resolution: {integrity: sha512-R8z6eTB55t3QeZMmU1C+Gv+t5UnNRkA55c5yo67fAVfxODxieTwsjNG7utxS/73NdP1NbDgCrhVEg2h00y4fFw==} + engines: {node: '>=10.13.0'} + glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} @@ -1734,6 +1845,9 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + gulp-sort@2.0.0: + resolution: {integrity: sha512-MyTel3FXOdh1qhw1yKhpimQrAmur9q1X0ZigLmCOxouQD+BD3za9/89O+HfbgBQvvh4igEbp0/PUWO+VqGYG1g==} + has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} @@ -1760,11 +1874,37 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + html-parse-stringify@3.0.1: + resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} + husky@9.1.7: resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} engines: {node: '>=18'} hasBin: true + i18next-browser-languagedetector@8.0.2: + resolution: {integrity: sha512-shBvPmnIyZeD2VU5jVGIOWP7u9qNG3Lj7mpaiPFpbJ3LVfHZJvVzKR4v1Cb91wAOFpNw442N+LGPzHOHsten2g==} + + i18next-http-backend@3.0.1: + resolution: {integrity: sha512-XT2lYSkbAtDE55c6m7CtKxxrsfuRQO3rUfHzj8ZyRtY9CkIX3aRGwXGTkUhpGWce+J8n7sfu3J0f2wTzo7Lw0A==} + + i18next-scanner@4.6.0: + resolution: {integrity: sha512-I/xKcwKfii3L3is3bUvfaIU0QA/wYhpZnjppfrzyb61QQddxkcpspASEtmfnxSYvE6yIaAxDlIxg0EHV7mxssg==} + engines: {node: '>=12'} + hasBin: true + + i18next@24.2.0: + resolution: {integrity: sha512-ArJJTS1lV6lgKH7yEf4EpgNZ7+THl7bsGxxougPYiXRTJ/Fe1j08/TBpV9QsXCIYVfdE/HWG/xLezJ5DOlfBOA==} + peerDependencies: + typescript: ^5 + peerDependenciesMeta: + typescript: + optional: true + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -1862,6 +2002,10 @@ packages: is-module@1.0.0: resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + is-negated-glob@1.0.0: + resolution: {integrity: sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==} + engines: {node: '>=0.10.0'} + is-negative-zero@2.0.3: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} @@ -1874,6 +2018,10 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-plain-object@2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + is-regex@1.2.0: resolution: {integrity: sha512-B6ohK4ZmoftlUe+uvenXSbPJFo6U37BH7oO1B3nQH8f/7h27N56s85MhUtbFJAziz5dcmuR3i8ovUl35zp8pFA==} engines: {node: '>= 0.4'} @@ -1898,6 +2046,10 @@ packages: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} + is-valid-glob@1.0.0: + resolution: {integrity: sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==} + engines: {node: '>=0.10.0'} + is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} @@ -1909,12 +2061,19 @@ packages: resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} engines: {node: '>= 0.4'} + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isobject@3.0.1: + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} + iterator.prototype@1.1.3: resolution: {integrity: sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==} engines: {node: '>= 0.4'} @@ -1975,6 +2134,10 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} @@ -1982,6 +2145,10 @@ packages: resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} engines: {node: '>=0.10'} + lead@4.0.0: + resolution: {integrity: sha512-DpMa59o5uGUWWjruMp71e6knmwKU3jRBBn1kjuLWN9EeIOxNeSAwvHf03WIl8g/ZMR2oSQC9ej3yeLBwdDc/pg==} + engines: {node: '>=10.13.0'} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -2016,6 +2183,9 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -2135,6 +2305,15 @@ packages: resolution: {integrity: sha512-qAGmXrM32xUGdaCBmkQG8RIgm+8Oj22rURkAoX9HuKDQiM0Vm66QebkWEnU5nozYgPbO/PFPrPmerI6ZEPp8UQ==} hasBin: true + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + node-releases@2.0.18: resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} @@ -2146,6 +2325,10 @@ packages: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} + now-and-later@3.0.0: + resolution: {integrity: sha512-pGO4pzSdaxhWTGkfSfHx3hVzJVslFPwBp2Myq9MYN/ChfJZF87ochMAXnvz6/58RJSf5ik2q9tXprBBrk2cpcg==} + engines: {node: '>= 10.13.0'} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -2220,6 +2403,9 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse5@6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -2436,6 +2622,9 @@ packages: resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} engines: {node: '>= 0.8'} + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -2449,6 +2638,9 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + queue-tick@1.0.1: + resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} + randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} @@ -2472,6 +2664,19 @@ packages: peerDependencies: react: ^19.0.0 + react-i18next@15.2.0: + resolution: {integrity: sha512-iJNc8111EaDtVTVMKigvBtPHyrJV+KblWG73cUxqp+WmJCcwkzhWNFXmkAD5pwP2Z4woeDj/oXDdbjDsb3Gutg==} + peerDependencies: + i18next: '>= 23.2.3' + react: '>= 16.8.0' + react-dom: '*' + react-native: '*' + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + react-icons@5.3.0: resolution: {integrity: sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==} peerDependencies: @@ -2491,6 +2696,9 @@ packages: read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} @@ -2503,10 +2711,20 @@ packages: resolution: {integrity: sha512-bMvFGIUKlc/eSfXNX+aZ+EL95/EgZzuwA0OBPTbZZDEJw/0AkentjMuM1oiRfwHrshqk4RzdgiTg5CcDalXN5g==} engines: {node: '>= 0.4'} + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + regexp.prototype.flags@1.5.3: resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} engines: {node: '>= 0.4'} + remove-trailing-separator@1.1.0: + resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} + + replace-ext@2.0.0: + resolution: {integrity: sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==} + engines: {node: '>= 10'} + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -2518,6 +2736,10 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve-options@2.0.0: + resolution: {integrity: sha512-/FopbmmFOQCfsCx77BRFdKOniglTiHumLgwvd6IDPihy1GKkadZbgQJBcTb2lMzSR1pndzd96b1nZrreZ7+9/A==} + engines: {node: '>= 10.13.0'} + resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} @@ -2545,6 +2767,9 @@ packages: resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} engines: {node: '>=0.4'} + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -2552,6 +2777,9 @@ packages: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} @@ -2585,6 +2813,10 @@ packages: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} + shallow-clone@3.0.1: + resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} + engines: {node: '>=8'} + sharp@0.33.5: resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -2628,6 +2860,10 @@ packages: smob@1.5.0: resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} + sortobject@4.17.0: + resolution: {integrity: sha512-gzx7USv55AFRQ7UCWJHHauwD/ptUHF9MLXCGO3f5M9zauDPZ/4a9H6/VVbOXefdpEoI1unwB/bArHIVMbWBHmA==} + engines: {node: '>=10'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -2639,10 +2875,16 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + stream-composer@1.0.2: + resolution: {integrity: sha512-bnBselmwfX5K10AH6L4c8+S5lgZMWI7ZYrz2rvYjCPB2DIMC4Ig8OpxGpNJSxRZ58oti7y1IcNvjBAz9vW5m4w==} + streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} + streamx@2.21.1: + resolution: {integrity: sha512-PhP9wUnFLa+91CPy3N6tiQsK+gnYyUNuk15S3YG/zjYE7RuPeCjJngqnzpC31ow0lzBHQ+QGO4cNJnd0djYUsw==} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -2673,6 +2915,9 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -2745,6 +2990,9 @@ packages: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} + teex@1.0.1: + resolution: {integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==} + terser-webpack-plugin@5.3.10: resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} engines: {node: '>= 10.13.0'} @@ -2766,6 +3014,9 @@ packages: engines: {node: '>=10'} hasBin: true + text-decoder@1.2.3: + resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + thenby@1.3.4: resolution: {integrity: sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ==} @@ -2776,6 +3027,12 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + through2@2.0.5: + resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + + through2@4.0.2: + resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} + tinycolor2@1.6.0: resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} @@ -2783,6 +3040,10 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + to-through@3.0.0: + resolution: {integrity: sha512-y8MN937s/HVhEoBU1SxfHC+wxCHkV1a9gW8eAdTadYh/bGyesZIVcbjI+mSpFbSVwQici/XjBjuUyri1dnXwBw==} + engines: {node: '>=10.13.0'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -2876,10 +3137,34 @@ packages: v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + value-or-function@4.0.0: + resolution: {integrity: sha512-aeVK81SIuT6aMJfNo9Vte8Dw0/FZINGBV8BfCraGtqVxIeLAEhJyoWs8SmvRVmXfGss2PmmOwZCuBPbZR+IYWg==} + engines: {node: '>= 10.13.0'} + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} + vinyl-contents@2.0.0: + resolution: {integrity: sha512-cHq6NnGyi2pZ7xwdHSW1v4Jfnho4TEGtxZHw01cmnc8+i7jgR6bRnED/LbrKan/Q7CvVLbnvA5OepnhbpjBZ5Q==} + engines: {node: '>=10.13.0'} + + vinyl-fs@4.0.0: + resolution: {integrity: sha512-7GbgBnYfaquMk3Qu9g22x000vbYkOex32930rBnc3qByw6HfMEAoELjCjoJv4HuEQxHAurT+nvMHm6MnJllFLw==} + engines: {node: '>=10.13.0'} + + vinyl-sourcemap@2.0.0: + resolution: {integrity: sha512-BAEvWxbBUXvlNoFQVFVHpybBbjW1r03WhohJzJDSfgrrK5xVYIDTan6xN14DlyImShgDRv2gl9qhM6irVMsV0Q==} + engines: {node: '>=10.13.0'} + + vinyl@3.0.0: + resolution: {integrity: sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==} + engines: {node: '>=10.13.0'} + + void-elements@3.1.0: + resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} + engines: {node: '>=0.10.0'} + watchpack@2.4.2: resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} engines: {node: '>=10.13.0'} @@ -2961,6 +3246,10 @@ packages: utf-8-validate: optional: true + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} @@ -3019,6 +3308,10 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@babel/runtime@7.26.0': + dependencies: + regenerator-runtime: 0.14.1 + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 @@ -3072,6 +3365,10 @@ snapshots: dependencies: '@tauri-apps/api': 2.1.1 + '@gulpjs/to-absolute-glob@4.0.0': + dependencies: + is-negated-glob: 1.0.0 + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.6': @@ -3719,14 +4016,39 @@ snapshots: '@zip.js/zip.js@2.7.53': {} + acorn-class-fields@0.3.7(acorn@8.14.0): + dependencies: + acorn: 8.14.0 + acorn-private-class-elements: 0.2.7(acorn@8.14.0) + acorn-jsx@5.3.2(acorn@8.14.0): dependencies: acorn: 8.14.0 + acorn-private-class-elements@0.2.7(acorn@8.14.0): + dependencies: + acorn: 8.14.0 + + acorn-private-methods@0.3.3(acorn@8.14.0): + dependencies: + acorn: 8.14.0 + acorn-private-class-elements: 0.2.7(acorn@8.14.0) + + acorn-stage3@4.0.0(acorn@8.14.0): + dependencies: + acorn: 8.14.0 + acorn-class-fields: 0.3.7(acorn@8.14.0) + acorn-private-methods: 0.3.3(acorn@8.14.0) + acorn-static-class-features: 0.2.4(acorn@8.14.0) + + acorn-static-class-features@0.2.4(acorn@8.14.0): + dependencies: + acorn: 8.14.0 + acorn-private-class-elements: 0.2.7(acorn@8.14.0) + acorn-walk@8.3.4: dependencies: acorn: 8.14.0 - optional: true acorn@8.14.0: {} @@ -3852,11 +4174,15 @@ snapshots: axobject-query@4.1.0: {} + b4a@1.6.7: {} + balanced-match@1.0.2: {} - base64-js@1.5.1: + bare-events@2.5.0: optional: true + base64-js@1.5.1: {} + big.js@5.2.2: {} binary-extensions@2.3.0: {} @@ -3868,6 +4194,12 @@ snapshots: readable-stream: 3.6.2 optional: true + bl@5.1.0: + dependencies: + buffer: 6.0.3 + inherits: 2.0.4 + readable-stream: 3.6.2 + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -3896,6 +4228,11 @@ snapshots: ieee754: 1.2.1 optional: true + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + busboy@1.6.0: dependencies: streamsearch: 1.1.0 @@ -3959,6 +4296,16 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + clone-deep@4.0.1: + dependencies: + is-plain-object: 2.0.4 + kind-of: 6.0.3 + shallow-clone: 3.0.1 + + clone-stats@1.0.0: {} + + clone@2.1.2: {} + clsx@2.1.1: {} color-convert@2.0.1: @@ -3983,14 +4330,20 @@ snapshots: commander@4.1.1: {} + commander@9.5.0: {} + common-tags@1.8.2: {} concat-map@0.0.1: {} construct-style-sheets-polyfill@3.1.0: {} + convert-source-map@2.0.0: {} + core-js@3.39.0: {} + core-util-is@1.0.3: {} + cors@2.8.5: dependencies: object-assign: 4.1.1 @@ -4017,6 +4370,12 @@ snapshots: create-require@1.1.1: optional: true + cross-fetch@4.0.0: + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -4157,6 +4516,10 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.2.1 + ensure-type@1.5.1: {} + + eol@0.9.1: {} + es-abstract@1.23.5: dependencies: array-buffer-byte-length: 1.0.1 @@ -4453,6 +4816,8 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.14.0) eslint-visitor-keys: 4.2.0 + esprima-next@5.8.4: {} + esquery@1.6.0: dependencies: estraverse: 5.3.0 @@ -4476,6 +4841,8 @@ snapshots: fast-deep-equal@3.1.3: {} + fast-fifo@1.3.2: {} + fast-glob@3.3.1: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -4553,6 +4920,11 @@ snapshots: jsonfile: 6.1.0 universalify: 2.0.1 + fs-mkdirp-stream@2.0.1: + dependencies: + graceful-fs: 4.2.11 + streamx: 2.21.1 + fsevents@2.3.3: optional: true @@ -4600,6 +4972,17 @@ snapshots: dependencies: is-glob: 4.0.3 + glob-stream@8.0.2: + dependencies: + '@gulpjs/to-absolute-glob': 4.0.0 + anymatch: 3.1.3 + fastq: 1.17.1 + glob-parent: 6.0.2 + is-glob: 4.0.3 + is-negated-glob: 1.0.0 + normalize-path: 3.0.0 + streamx: 2.21.1 + glob-to-regexp@0.4.1: {} glob2base@0.0.12: @@ -4650,6 +5033,10 @@ snapshots: graphemer@1.4.0: {} + gulp-sort@2.0.0: + dependencies: + through2: 2.0.5 + has-bigints@1.0.2: {} has-flag@4.0.0: {} @@ -4670,10 +5057,57 @@ snapshots: dependencies: function-bind: 1.1.2 + html-parse-stringify@3.0.1: + dependencies: + void-elements: 3.1.0 + husky@9.1.7: {} - ieee754@1.2.1: - optional: true + i18next-browser-languagedetector@8.0.2: + dependencies: + '@babel/runtime': 7.26.0 + + i18next-http-backend@3.0.1: + dependencies: + cross-fetch: 4.0.0 + transitivePeerDependencies: + - encoding + + i18next-scanner@4.6.0(typescript@5.7.2): + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + acorn-stage3: 4.0.0(acorn@8.14.0) + acorn-walk: 8.3.4 + chalk: 4.1.2 + clone-deep: 4.0.1 + commander: 9.5.0 + deepmerge: 4.3.1 + ensure-type: 1.5.1 + eol: 0.9.1 + esprima-next: 5.8.4 + gulp-sort: 2.0.0 + i18next: 24.2.0(typescript@5.7.2) + lodash: 4.17.21 + parse5: 6.0.1 + sortobject: 4.17.0 + through2: 4.0.2 + vinyl: 3.0.0 + vinyl-fs: 4.0.0 + transitivePeerDependencies: + - typescript + + i18next@24.2.0(typescript@5.7.2): + dependencies: + '@babel/runtime': 7.26.0 + optionalDependencies: + typescript: 5.7.2 + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} ignore@5.3.2: {} @@ -4686,8 +5120,7 @@ snapshots: imurmurhash@0.1.4: {} - inherits@2.0.4: - optional: true + inherits@2.0.4: {} ini@1.3.8: optional: true @@ -4761,6 +5194,8 @@ snapshots: is-module@1.0.0: {} + is-negated-glob@1.0.0: {} + is-negative-zero@2.0.3: {} is-number-object@1.0.7: @@ -4769,6 +5204,10 @@ snapshots: is-number@7.0.0: {} + is-plain-object@2.0.4: + dependencies: + isobject: 3.0.1 + is-regex@1.2.0: dependencies: call-bind: 1.0.7 @@ -4794,6 +5233,8 @@ snapshots: dependencies: which-typed-array: 1.1.16 + is-valid-glob@1.0.0: {} + is-weakmap@2.0.2: {} is-weakref@1.0.2: @@ -4805,10 +5246,14 @@ snapshots: call-bind: 1.0.7 get-intrinsic: 1.2.4 + isarray@1.0.0: {} + isarray@2.0.5: {} isexe@2.0.0: {} + isobject@3.0.1: {} + iterator.prototype@1.1.3: dependencies: define-properties: 1.2.1 @@ -4874,12 +5319,16 @@ snapshots: dependencies: json-buffer: 3.0.1 + kind-of@6.0.3: {} + language-subtag-registry@0.3.23: {} language-tags@1.0.9: dependencies: language-subtag-registry: 0.3.23 + lead@4.0.0: {} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -4909,6 +5358,8 @@ snapshots: lodash.merge@4.6.2: {} + lodash@4.17.21: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -5028,12 +5479,20 @@ snapshots: transitivePeerDependencies: - supports-color + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + node-releases@2.0.18: {} normalize-path@3.0.0: {} normalize-range@0.1.2: {} + now-and-later@3.0.0: + dependencies: + once: 1.4.0 + object-assign@4.1.1: {} object-hash@3.0.0: {} @@ -5077,7 +5536,6 @@ snapshots: once@1.4.0: dependencies: wrappy: 1.0.2 - optional: true optionator@0.9.4: dependencies: @@ -5114,6 +5572,8 @@ snapshots: dependencies: callsites: 3.1.0 + parse5@6.0.1: {} + path-exists@4.0.0: {} path-key@3.1.1: {} @@ -5274,6 +5734,8 @@ snapshots: pretty-hrtime@1.0.3: {} + process-nextick-args@2.0.1: {} + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 @@ -5290,6 +5752,8 @@ snapshots: queue-microtask@1.2.3: {} + queue-tick@1.0.1: {} + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 @@ -5319,6 +5783,15 @@ snapshots: react: 19.0.0 scheduler: 0.25.0 + react-i18next@15.2.0(i18next@24.2.0(typescript@5.7.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + dependencies: + '@babel/runtime': 7.26.0 + html-parse-stringify: 3.0.1 + i18next: 24.2.0(typescript@5.7.2) + react: 19.0.0 + optionalDependencies: + react-dom: 19.0.0(react@19.0.0) + react-icons@5.3.0(react@19.0.0): dependencies: react: 19.0.0 @@ -5335,12 +5808,21 @@ snapshots: dependencies: pify: 2.3.0 + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + readable-stream@3.6.2: dependencies: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 - optional: true readdirp@3.6.0: dependencies: @@ -5356,6 +5838,8 @@ snapshots: gopd: 1.1.0 which-builtin-type: 1.2.0 + regenerator-runtime@0.14.1: {} + regexp.prototype.flags@1.5.3: dependencies: call-bind: 1.0.7 @@ -5363,12 +5847,20 @@ snapshots: es-errors: 1.3.0 set-function-name: 2.0.2 + remove-trailing-separator@1.1.0: {} + + replace-ext@2.0.0: {} + require-directory@2.1.1: {} require-main-filename@2.0.0: {} resolve-from@4.0.0: {} + resolve-options@2.0.0: + dependencies: + value-or-function: 4.0.0 + resolve-pkg-maps@1.0.0: {} resolve@1.22.8: @@ -5420,6 +5912,8 @@ snapshots: has-symbols: 1.0.3 isarray: 2.0.5 + safe-buffer@5.1.2: {} + safe-buffer@5.2.1: {} safe-regex-test@1.0.3: @@ -5428,6 +5922,8 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.0 + safer-buffer@2.1.2: {} + scheduler@0.23.2: dependencies: loose-envify: 1.4.0 @@ -5466,6 +5962,10 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + shallow-clone@3.0.1: + dependencies: + kind-of: 6.0.3 + sharp@0.33.5: dependencies: color: 4.2.3 @@ -5536,6 +6036,8 @@ snapshots: smob@1.5.0: {} + sortobject@4.17.0: {} + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -5545,8 +6047,20 @@ snapshots: source-map@0.6.1: {} + stream-composer@1.0.2: + dependencies: + streamx: 2.21.1 + streamsearch@1.1.0: {} + streamx@2.21.1: + dependencies: + fast-fifo: 1.3.2 + queue-tick: 1.0.1 + text-decoder: 1.2.3 + optionalDependencies: + bare-events: 2.5.0 + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -5604,10 +6118,13 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 - optional: true strip-ansi@6.0.1: dependencies: @@ -5699,6 +6216,10 @@ snapshots: readable-stream: 3.6.2 optional: true + teex@1.0.1: + dependencies: + streamx: 2.21.1 + terser-webpack-plugin@5.3.10(webpack@5.96.1): dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -5715,6 +6236,10 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 + text-decoder@1.2.3: + dependencies: + b4a: 1.6.7 + thenby@1.3.4: {} thenify-all@1.6.0: @@ -5725,12 +6250,25 @@ snapshots: dependencies: any-promise: 1.3.0 + through2@2.0.5: + dependencies: + readable-stream: 2.3.8 + xtend: 4.0.2 + + through2@4.0.2: + dependencies: + readable-stream: 3.6.2 + tinycolor2@1.6.0: {} to-regex-range@5.0.1: dependencies: is-number: 7.0.0 + to-through@3.0.0: + dependencies: + streamx: 2.21.1 + tr46@0.0.3: {} ts-api-utils@1.4.3(typescript@5.7.2): @@ -5841,8 +6379,51 @@ snapshots: v8-compile-cache-lib@3.0.1: optional: true + value-or-function@4.0.0: {} + vary@1.1.2: {} + vinyl-contents@2.0.0: + dependencies: + bl: 5.1.0 + vinyl: 3.0.0 + + vinyl-fs@4.0.0: + dependencies: + fs-mkdirp-stream: 2.0.1 + glob-stream: 8.0.2 + graceful-fs: 4.2.11 + iconv-lite: 0.6.3 + is-valid-glob: 1.0.0 + lead: 4.0.0 + normalize-path: 3.0.0 + resolve-options: 2.0.0 + stream-composer: 1.0.2 + streamx: 2.21.1 + to-through: 3.0.0 + value-or-function: 4.0.0 + vinyl: 3.0.0 + vinyl-sourcemap: 2.0.0 + + vinyl-sourcemap@2.0.0: + dependencies: + convert-source-map: 2.0.0 + graceful-fs: 4.2.11 + now-and-later: 3.0.0 + streamx: 2.21.1 + vinyl: 3.0.0 + vinyl-contents: 2.0.0 + + vinyl@3.0.0: + dependencies: + clone: 2.1.2 + clone-stats: 1.0.0 + remove-trailing-separator: 1.1.0 + replace-ext: 2.0.0 + teex: 1.0.1 + + void-elements@3.1.0: {} + watchpack@2.4.2: dependencies: glob-to-regexp: 0.4.1 @@ -5954,11 +6535,12 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.1.0 - wrappy@1.0.2: - optional: true + wrappy@1.0.2: {} ws@8.18.0: {} + xtend@4.0.2: {} + y18n@4.0.3: {} y18n@5.0.8: {}