Add i18n support (#46)
This commit is contained in:
@@ -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,
|
||||
},
|
||||
};
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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": "ライブラリー"
|
||||
}
|
||||
@@ -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": "내 서재"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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": "Ваша библиотека"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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": "书库"
|
||||
}
|
||||
@@ -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": "書庫"
|
||||
}
|
||||
@@ -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 (
|
||||
<html lang='en'>
|
||||
<html>
|
||||
<head>
|
||||
<title>{title}</title>
|
||||
<meta name='mobile-web-app-capable' content='yes' />
|
||||
|
||||
@@ -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<BookshelfProps> = ({ libraryBooks, isSelectMode, onImportBooks }) => {
|
||||
const _ = useTranslation();
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const { envConfig, appService } = useEnv();
|
||||
@@ -153,14 +155,14 @@ const Bookshelf: React.FC<BookshelfProps> = ({ 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<BookshelfProps> = ({ libraryBooks, isSelectMode, onImp
|
||||
className='book-item cursor-pointer'
|
||||
onContextMenu={bookContextMenuHandler.bind(null, item as Book)}
|
||||
>
|
||||
<div key={(item as Book).hash}
|
||||
<div
|
||||
key={(item as Book).hash}
|
||||
className='bg-base-100 shadow-md'
|
||||
onClick={() => handleBookClick(item.hash)}
|
||||
>
|
||||
@@ -276,11 +279,11 @@ const Bookshelf: React.FC<BookshelfProps> = ({ libraryBooks, isSelectMode, onImp
|
||||
<div className='text-base-content bg-base-300 fixed bottom-4 left-1/2 flex -translate-x-1/2 transform space-x-4 rounded-lg p-4 shadow-lg'>
|
||||
<button onClick={openSelectedBooks} className='flex items-center space-x-2'>
|
||||
<MdOpenInNew />
|
||||
<span>Open</span>
|
||||
<span>{_('Open')}</span>
|
||||
</button>
|
||||
<button onClick={deleteSelectedBooks} className='flex items-center space-x-2'>
|
||||
<MdDelete className='fill-red-500' />
|
||||
<span className='text-red-500'>Delete</span>
|
||||
<span className='text-red-500'>{_('Delete')}</span>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
@@ -291,16 +294,15 @@ const Bookshelf: React.FC<BookshelfProps> = ({ libraryBooks, isSelectMode, onImp
|
||||
)}
|
||||
{showDeleteAlert && (
|
||||
<Alert
|
||||
title='Confirm Deletion'
|
||||
title={_('Confirm Deletion')}
|
||||
message='Are you sure to delete the selected books?'
|
||||
onClickCancel={() => setShowDeleteAlert(false)}
|
||||
onClickConfirm={confirmDelete}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Modal Component */}
|
||||
|
||||
{selectedBook && (
|
||||
<BookDetailModal isOpen={isModalOpen} onClose={closeModal} book={selectedBook} envConfig={envConfig} />
|
||||
<BookDetailModal isOpen={isModalOpen} book={selectedBook} onClose={closeModal} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -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<LibraryHeaderProps> = ({
|
||||
onImportBooks,
|
||||
onToggleSelectMode,
|
||||
}) => {
|
||||
const _ = useTranslation();
|
||||
const { appService } = useEnv();
|
||||
const { isTrafficLightVisible } = useTrafficLight();
|
||||
const headerRef = useRef<HTMLDivElement>(null);
|
||||
@@ -53,7 +55,7 @@ const LibraryHeader: React.FC<LibraryHeaderProps> = ({
|
||||
</span>
|
||||
<input
|
||||
type='text'
|
||||
placeholder='Search books...'
|
||||
placeholder={_('Search books...')}
|
||||
spellCheck='false'
|
||||
className={clsx(
|
||||
'input rounded-badge bg-base-300/50 h-7 w-full pl-10 pr-10',
|
||||
@@ -73,13 +75,20 @@ const LibraryHeader: React.FC<LibraryHeaderProps> = ({
|
||||
>
|
||||
<li>
|
||||
<button className='text-base-content' onClick={onImportBooks}>
|
||||
From Local File
|
||||
{_('From Local File')}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button onClick={onToggleSelectMode} aria-label='Select Multiple Books' className='h-6'>
|
||||
<div className='lg:tooltip lg:tooltip-bottom cursor-pointer' data-tip='Select books'>
|
||||
<button
|
||||
onClick={onToggleSelectMode}
|
||||
aria-label={_('Select multiple books')}
|
||||
className='h-6'
|
||||
>
|
||||
<div
|
||||
className='lg:tooltip lg:tooltip-bottom cursor-pointer'
|
||||
data-tip={_('Select books')}
|
||||
>
|
||||
<PiSelectionAllDuotone
|
||||
role='button'
|
||||
className={`h-6 w-6 ${isSelectMode ? 'fill-gray-400' : 'fill-gray-500'}`}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { DOWNLOAD_READEST_URL } from '@/services/constants';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import MenuItem from '@/components/MenuItem';
|
||||
|
||||
interface BookMenuProps {
|
||||
@@ -17,6 +18,7 @@ interface BookMenuProps {
|
||||
}
|
||||
|
||||
const SettingsMenu: React.FC<BookMenuProps> = ({ setIsDropdownOpen }) => {
|
||||
const _ = useTranslation();
|
||||
const router = useRouter();
|
||||
const { envConfig } = useEnv();
|
||||
const { user, logout } = useAuth();
|
||||
@@ -56,13 +58,17 @@ const SettingsMenu: React.FC<BookMenuProps> = ({ setIsDropdownOpen }) => {
|
||||
>
|
||||
{user ? (
|
||||
<MenuItem
|
||||
label={userDisplayName ? `Logged in as ${userDisplayName}` : 'Logged in'}
|
||||
label={
|
||||
userDisplayName
|
||||
? _('Logged in as {{userDisplayName}}', { userDisplayName })
|
||||
: _('Logged in')
|
||||
}
|
||||
labelClass='!max-w-40'
|
||||
icon={
|
||||
avatarUrl ? (
|
||||
<Image
|
||||
src={avatarUrl}
|
||||
alt='User Avatar'
|
||||
alt={_('User avatar')}
|
||||
className='h-5 w-5 rounded-full'
|
||||
referrerPolicy='no-referrer'
|
||||
width={20}
|
||||
@@ -74,19 +80,19 @@ const SettingsMenu: React.FC<BookMenuProps> = ({ setIsDropdownOpen }) => {
|
||||
}
|
||||
>
|
||||
<ul>
|
||||
<MenuItem label='Sign Out' noIcon onClick={handleUserLogout} />
|
||||
<MenuItem label={_('Sign Out')} noIcon onClick={handleUserLogout} />
|
||||
</ul>
|
||||
</MenuItem>
|
||||
) : (
|
||||
<MenuItem
|
||||
label='Sign In'
|
||||
label={_('Sign In')}
|
||||
icon={<PiUserCircle size={20} />}
|
||||
onClick={handleUserLogin}
|
||||
></MenuItem>
|
||||
)}
|
||||
<hr className='border-base-200 my-1' />
|
||||
{isWebApp && <MenuItem label='Download Readest' onClick={downloadReadest} />}
|
||||
<MenuItem label='About Readest' onClick={showAboutReadest} />
|
||||
{isWebApp && <MenuItem label={_('Download Readest')} onClick={downloadReadest} />}
|
||||
<MenuItem label={_('About Readest')} onClick={showAboutReadest} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@ import { FILE_ACCEPT_FORMATS, SUPPORTED_FILE_EXTS } from '@/services/constants';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
import { useTheme } from '@/hooks/useTheme';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { useLibraryStore } from '@/store/libraryStore';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { useDemoBooks } from './hooks/useDemoBooks';
|
||||
@@ -35,6 +36,7 @@ const LibraryPage = () => {
|
||||
clearOpenWithBooks,
|
||||
} = useLibraryStore();
|
||||
useTheme();
|
||||
const _ = useTranslation();
|
||||
const { setSettings, saveSettings } = useSettingsStore();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const isInitiating = useRef(false);
|
||||
@@ -237,12 +239,14 @@ const LibraryPage = () => {
|
||||
<div className='hero h-screen items-center justify-center'>
|
||||
<div className='hero-content text-neutral-content text-center'>
|
||||
<div className='max-w-md'>
|
||||
<h1 className='mb-5 text-5xl font-bold'>Your Library</h1>
|
||||
<h1 className='mb-5 text-5xl font-bold'>{_('Your Library')}</h1>
|
||||
<p className='mb-5'>
|
||||
Welcome to your library. You can import your books here and read them anytime.
|
||||
{_(
|
||||
'Welcome to your library. You can import your books here and read them anytime.',
|
||||
)}
|
||||
</p>
|
||||
<button className='btn btn-primary rounded-xl' onClick={handleImportBooks}>
|
||||
Import Books
|
||||
{_('Import Books')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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<BookmarkTogglerProps> = ({ bookKey }) => {
|
||||
const _ = useTranslation();
|
||||
const { envConfig } = useEnv();
|
||||
const { settings } = useSettingsStore();
|
||||
const { getConfig, saveConfig, updateBooknotes } = useBookDataStore();
|
||||
@@ -98,7 +100,7 @@ const BookmarkToggler: React.FC<BookmarkTogglerProps> = ({ bookKey }) => {
|
||||
)
|
||||
}
|
||||
onClick={toggleBookmark}
|
||||
tooltip='Bookmark'
|
||||
tooltip={_('Bookmark')}
|
||||
tooltipDirection='bottom'
|
||||
></Button>
|
||||
);
|
||||
|
||||
@@ -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<FooterBarProps> = ({ 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<FooterBarProps> = ({ bookKey, pageinfo, isHoveredAnim
|
||||
onMouseEnter={() => setHoveredBookKey(bookKey)}
|
||||
onMouseLeave={() => setHoveredBookKey('')}
|
||||
>
|
||||
<Button icon={<RiArrowLeftWideLine size={20} />} onClick={handleGoPrev} tooltip='Go Left' />
|
||||
<Button
|
||||
icon={<RiArrowLeftWideLine size={20} />}
|
||||
onClick={handleGoPrev}
|
||||
tooltip={_('Go Left')}
|
||||
/>
|
||||
<Button
|
||||
icon={<RiArrowGoBackLine size={20} />}
|
||||
onClick={handleGoBack}
|
||||
tooltip='Go Back'
|
||||
tooltip={_('Go Back')}
|
||||
disabled={!view?.history.canGoBack}
|
||||
/>
|
||||
<Button
|
||||
icon={<RiArrowGoForwardLine size={20} />}
|
||||
onClick={handleGoForward}
|
||||
tooltip='Go Forward'
|
||||
tooltip={_('Go Forward')}
|
||||
disabled={!view?.history.canGoForward}
|
||||
/>
|
||||
<span className='mx-2 text-center text-sm'>
|
||||
@@ -77,7 +83,11 @@ const FooterBar: React.FC<FooterBarProps> = ({ bookKey, pageinfo, isHoveredAnim
|
||||
value={pageinfoValid ? progressFraction * 100 : 0}
|
||||
onChange={(e) => handleProgressChange(e)}
|
||||
/>
|
||||
<Button icon={<RiArrowRightWideLine size={20} />} onClick={handleGoNext} tooltip='Go Right' />
|
||||
<Button
|
||||
icon={<RiArrowRightWideLine size={20} />}
|
||||
onClick={handleGoNext}
|
||||
tooltip={_('Go Right')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ import { TbLayoutSidebarRight, TbLayoutSidebarRightFilled } from 'react-icons/tb
|
||||
|
||||
import { useSidebarStore } from '@/store/sidebarStore';
|
||||
import { useNotebookStore } from '@/store/notebookStore';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import Button from '@/components/Button';
|
||||
|
||||
interface NotebookTogglerProps {
|
||||
@@ -10,6 +11,7 @@ interface NotebookTogglerProps {
|
||||
}
|
||||
|
||||
const NotebookToggler: React.FC<NotebookTogglerProps> = ({ bookKey }) => {
|
||||
const _ = useTranslation();
|
||||
const { sideBarBookKey, setSideBarBookKey } = useSidebarStore();
|
||||
const { isNotebookVisible, toggleNotebook } = useNotebookStore();
|
||||
const handleToggleSidebar = () => {
|
||||
@@ -30,7 +32,7 @@ const NotebookToggler: React.FC<NotebookTogglerProps> = ({ bookKey }) => {
|
||||
)
|
||||
}
|
||||
onClick={handleToggleSidebar}
|
||||
tooltip='Notebook'
|
||||
tooltip={_('Notebook')}
|
||||
tooltipDirection='bottom'
|
||||
></Button>
|
||||
);
|
||||
|
||||
@@ -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<PageInfoProps> = ({ 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 (
|
||||
|
||||
@@ -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<SidebarTogglerProps> = ({ bookKey }) => {
|
||||
const _ = useTranslation();
|
||||
const { sideBarBookKey, isSideBarVisible, setSideBarBookKey, toggleSideBar } = useSidebarStore();
|
||||
const handleToggleSidebar = () => {
|
||||
if (sideBarBookKey === bookKey) {
|
||||
@@ -28,7 +30,7 @@ const SidebarToggler: React.FC<SidebarTogglerProps> = ({ bookKey }) => {
|
||||
)
|
||||
}
|
||||
onClick={handleToggleSidebar}
|
||||
tooltip='Sidebar'
|
||||
tooltip={_('Sidebar')}
|
||||
tooltipDirection='bottom'
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -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<ViewMenuProps> = ({
|
||||
setIsDropdownOpen,
|
||||
onSetSettingsDialogOpen,
|
||||
}) => {
|
||||
const _ = useTranslation();
|
||||
const { getView, getViews, getViewSettings, setViewSettings } = useReaderStore();
|
||||
const viewSettings = getViewSettings(bookKey)!;
|
||||
|
||||
@@ -126,10 +128,10 @@ const ViewMenu: React.FC<ViewMenuProps> = ({
|
||||
|
||||
<hr className='border-base-200 my-1' />
|
||||
|
||||
<MenuItem label='Font & Layout' shortcut='Shift+F' onClick={openFontLayoutMenu} />
|
||||
<MenuItem label={_('Font & Layout')} shortcut='Shift+F' onClick={openFontLayoutMenu} />
|
||||
|
||||
<MenuItem
|
||||
label='Scrolled Mode'
|
||||
label={_('Scrolled Mode')}
|
||||
shortcut='Shift+J'
|
||||
icon={isScrolledMode ? <MdCheck size={20} /> : undefined}
|
||||
onClick={toggleScrolledMode}
|
||||
@@ -139,7 +141,11 @@ const ViewMenu: React.FC<ViewMenuProps> = ({
|
||||
|
||||
<MenuItem
|
||||
label={
|
||||
themeMode === 'dark' ? 'Dark Mode' : themeMode === 'light' ? 'Light Mode' : 'Auto Mode'
|
||||
themeMode === 'dark'
|
||||
? _('Dark Mode')
|
||||
: themeMode === 'light'
|
||||
? _('Light Mode')
|
||||
: _('Auto Mode')
|
||||
}
|
||||
icon={
|
||||
themeMode === 'dark' ? (
|
||||
@@ -153,7 +159,7 @@ const ViewMenu: React.FC<ViewMenuProps> = ({
|
||||
onClick={cycleThemeMode}
|
||||
/>
|
||||
<MenuItem
|
||||
label='Invert Colors in Dark Mode'
|
||||
label={_('Invert Colors in Dark Mode')}
|
||||
icon={isInvertedColors ? <MdCheck size={20} className='text-base-content' /> : undefined}
|
||||
onClick={toggleInvertedColors}
|
||||
disabled={!isDarkMode}
|
||||
|
||||
@@ -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 }) => (
|
||||
<div className='notebook-header relative flex h-11 items-center px-3'>
|
||||
<div className='absolute inset-0 flex items-center justify-center'>
|
||||
<div className='notebook-title text-sm font-medium'>Notebook</div>
|
||||
}> = ({ isPinned, handleTogglePin }) => {
|
||||
const _ = useTranslation();
|
||||
return (
|
||||
<div className='notebook-header relative flex h-11 items-center px-3'>
|
||||
<div className='absolute inset-0 flex items-center justify-center'>
|
||||
<div className='notebook-title text-sm font-medium'>{_('Notebook')}</div>
|
||||
</div>
|
||||
<div className='z-10 flex items-center space-x-3'>
|
||||
<button
|
||||
onClick={handleTogglePin}
|
||||
className={`${isPinned ? 'bg-base-300' : 'bg-base-300/65'} btn btn-ghost btn-circle h-6 min-h-6 w-6`}
|
||||
>
|
||||
{isPinned ? <MdPushPin size={14} /> : <MdOutlinePushPin size={14} />}
|
||||
</button>
|
||||
<button className='btn btn-ghost left-0 h-8 min-h-8 w-8 p-0'>
|
||||
<FiSearch size={18} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className='z-10 flex items-center space-x-3'>
|
||||
<button
|
||||
onClick={handleTogglePin}
|
||||
className={`${isPinned ? 'bg-base-300' : 'bg-base-300/65'} btn btn-ghost btn-circle h-6 min-h-6 w-6`}
|
||||
>
|
||||
{isPinned ? <MdPushPin size={14} /> : <MdOutlinePushPin size={14} />}
|
||||
</button>
|
||||
<button className='btn btn-ghost left-0 h-8 min-h-8 w-8 p-0'>
|
||||
<FiSearch size={18} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
export default NotebookHeader;
|
||||
|
||||
@@ -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<NoteEditorProps> = ({ onSave, onEdit }) => {
|
||||
const _ = useTranslation();
|
||||
const { notebookNewAnnotation, notebookEditAnnotation } = useNotebookStore();
|
||||
const editorRef = useRef<HTMLTextAreaElement>(null);
|
||||
const [note, setNote] = React.useState('');
|
||||
@@ -62,7 +64,7 @@ const NoteEditor: React.FC<NoteEditorProps> = ({ onSave, onEdit }) => {
|
||||
rows={1}
|
||||
spellCheck={false}
|
||||
onChange={handleChange}
|
||||
placeholder='Add your notes here...'
|
||||
placeholder={_('Add your notes here...')}
|
||||
></textarea>
|
||||
</div>
|
||||
<button
|
||||
@@ -73,7 +75,7 @@ const NoteEditor: React.FC<NoteEditorProps> = ({ onSave, onEdit }) => {
|
||||
)}
|
||||
onClick={handleSaveNote}
|
||||
>
|
||||
<div className='pr-1 align-bottom text-xs text-blue-400'>Save</div>
|
||||
<div className='pr-1 align-bottom text-xs text-blue-400'>{_('Save')}</div>
|
||||
</button>
|
||||
</div>
|
||||
<div className='flex items-start pt-2'>
|
||||
|
||||
@@ -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 = ({}) => {
|
||||
/>
|
||||
<NotebookHeader isPinned={isNotebookPinned} handleTogglePin={handleTogglePin} />
|
||||
<div className='max-h-[calc(100vh-44px)] overflow-y-auto px-3'>
|
||||
<div>{excerptNotes.length > 0 && <p className='pt-1 text-sm'>Excerpts</p>}</div>
|
||||
<div>{excerptNotes.length > 0 && <p className='pt-1 text-sm'>{_('Excerpts')}</p>}</div>
|
||||
<ul className=''>
|
||||
{excerptNotes.map((item, index) => (
|
||||
<li key={`${index}-${item.id}`} className='my-2'>
|
||||
@@ -171,7 +173,7 @@ const Notebook: React.FC = ({}) => {
|
||||
)}
|
||||
onClick={handleEditNote.bind(null, item, true)}
|
||||
>
|
||||
<div className='align-bottom text-xs text-red-400'>Delete</div>
|
||||
<div className='align-bottom text-xs text-red-400'>{_('Delete')}</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -181,7 +183,7 @@ const Notebook: React.FC = ({}) => {
|
||||
</ul>
|
||||
<div>
|
||||
{(notebookNewAnnotation || annotationNotes.length > 0) && (
|
||||
<p className='pt-1 text-sm'>Notes</p>
|
||||
<p className='pt-1 text-sm'>{_('Notes')}</p>
|
||||
)}
|
||||
</div>
|
||||
{(notebookNewAnnotation || notebookEditAnnotation) && (
|
||||
|
||||
@@ -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 (
|
||||
<div className='my-4 w-full space-y-6'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<h2 className='font-medium'>Theme Mode</h2>
|
||||
<h2 className='font-medium'>{_('Theme Mode')}</h2>
|
||||
<div className='flex gap-2'>
|
||||
<div className='tooltip tooltip-bottom' data-tip='Auto Mode'>
|
||||
<div className='tooltip tooltip-bottom' data-tip={_('Auto Mode')}>
|
||||
<button
|
||||
className={`btn btn-ghost btn-circle ${themeMode === 'auto' ? 'btn-active bg-base-300' : ''}`}
|
||||
onClick={() => updateThemeMode('auto')}
|
||||
@@ -35,7 +37,7 @@ const ColorPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className='tooltip tooltip-bottom' data-tip='Light Mode'>
|
||||
<div className='tooltip tooltip-bottom' data-tip={_('Light Mode')}>
|
||||
<button
|
||||
className={`btn btn-ghost btn-circle ${themeMode === 'light' ? 'btn-active bg-base-300' : ''}`}
|
||||
onClick={() => updateThemeMode('light')}
|
||||
@@ -44,7 +46,7 @@ const ColorPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className='tooltip tooltip-bottom' data-tip='Dark Mode'>
|
||||
<div className='tooltip tooltip-bottom' data-tip={_('Dark Mode')}>
|
||||
<button
|
||||
className={`btn btn-ghost btn-circle ${themeMode === 'dark' ? 'btn-active bg-base-300' : ''}`}
|
||||
onClick={() => updateThemeMode('dark')}
|
||||
@@ -56,7 +58,7 @@ const ColorPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 className='mb-2 font-medium'>Theme Color</h2>
|
||||
<h2 className='mb-2 font-medium'>{_('Theme Color')}</h2>
|
||||
<div className='grid grid-cols-3 gap-4'>
|
||||
{themes.map(({ name, label, colors }) => (
|
||||
<label
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import React from 'react';
|
||||
import { MdCheck } from 'react-icons/md';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
|
||||
interface DialogMenuProps {
|
||||
toggleDropdown?: () => void;
|
||||
}
|
||||
|
||||
const DialogMenu: React.FC<DialogMenuProps> = ({ toggleDropdown }) => {
|
||||
const _ = useTranslation();
|
||||
const { isFontLayoutSettingsGlobal, setFontLayoutSettingsGlobal } = useSettingsStore();
|
||||
|
||||
const handleToggleGlobal = () => {
|
||||
@@ -28,7 +30,7 @@ const DialogMenu: React.FC<DialogMenuProps> = ({ toggleDropdown }) => {
|
||||
{isFontLayoutSettingsGlobal && <MdCheck size={20} className='text-base-content' />}
|
||||
</span>
|
||||
<div className='tooltip' data-tip='Uncheck for current book settings'>
|
||||
<span className='ml-2'>Global Settings</span>
|
||||
<span className='ml-2'>{_('Global Settings')}</span>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -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 (
|
||||
<div className='my-4 w-full space-y-6'>
|
||||
<div className='w-full'>
|
||||
<h2 className='mb-2 font-medium'>Font Size</h2>
|
||||
<h2 className='mb-2 font-medium'>{_('Font Size')}</h2>
|
||||
<div className='card border-base-200 border shadow'>
|
||||
<div className='divide-base-200 divide-y'>
|
||||
<NumberInput
|
||||
@@ -169,11 +171,11 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
</div>
|
||||
|
||||
<div className='w-full'>
|
||||
<h2 className='mb-2 font-medium'>Font Family</h2>
|
||||
<h2 className='mb-2 font-medium'>{_('Font Family')}</h2>
|
||||
<div className='card border-base-200 border shadow'>
|
||||
<div className='divide-base-200 divide-y'>
|
||||
<div className='config-item config-item-top'>
|
||||
<span className=''>Default Font</span>
|
||||
<span className=''>{_('Default Font')}</span>
|
||||
<FontDropdown
|
||||
options={fontFamilyOptions}
|
||||
selected={defaultFont}
|
||||
@@ -183,7 +185,7 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
</div>
|
||||
|
||||
<div className='config-item config-item-bottom'>
|
||||
<span className=''>Override Publisher Font</span>
|
||||
<span className=''>{_('Override Publisher Font')}</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
className='toggle'
|
||||
@@ -196,20 +198,20 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
</div>
|
||||
|
||||
<div className='w-full'>
|
||||
<h2 className='mb-2 font-medium'>Font Face</h2>
|
||||
<h2 className='mb-2 font-medium'>{_('Font Face')}</h2>
|
||||
<div className='card border-base-200 border shadow'>
|
||||
<div className='divide-base-200 divide-y'>
|
||||
<FontFace
|
||||
className='config-item-top'
|
||||
family='serif'
|
||||
label='Serif Font'
|
||||
label={_('Serif Font')}
|
||||
options={SERIF_FONTS}
|
||||
selected={serifFont}
|
||||
onSelect={setSerifFont}
|
||||
/>
|
||||
<FontFace
|
||||
family='sans-serif'
|
||||
label='Sans-Serif Font'
|
||||
label={_('Sans-Serif Font')}
|
||||
options={SANS_SERIF_FONTS}
|
||||
selected={sansSerifFont}
|
||||
onSelect={setSansSerifFont}
|
||||
@@ -217,7 +219,7 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
<FontFace
|
||||
className='config-item-bottom'
|
||||
family='monospace'
|
||||
label='Monospace Font'
|
||||
label={_('Monospace Font')}
|
||||
options={MONOSPACE_FONTS}
|
||||
selected={monospaceFont}
|
||||
onSelect={setMonospaceFont}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { getStyles } from '@/utils/style';
|
||||
import { ONE_COLUMN_MAX_INLINE_SIZE } from '@/services/constants';
|
||||
import NumberInput from './NumberInput';
|
||||
import { useTheme } from '@/hooks/useTheme';
|
||||
|
||||
const LayoutPanel: React.FC<{ bookKey: string }> = ({ 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 (
|
||||
<div className='my-4 w-full space-y-6'>
|
||||
<div className='w-full'>
|
||||
<h2 className='mb-2 font-medium'>Paragraph</h2>
|
||||
<h2 className='mb-2 font-medium'>{_('Paragraph')}</h2>
|
||||
<div className='card bg-base-100 border-base-200 border shadow'>
|
||||
<div className='divide-base-200 divide-y'>
|
||||
<NumberInput
|
||||
@@ -125,7 +127,7 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
step={0.1}
|
||||
/>
|
||||
<div className='config-item config-item-bottom'>
|
||||
<span className=''>Full Justification</span>
|
||||
<span className=''>{_('Full Justification')}</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
className='toggle'
|
||||
@@ -134,7 +136,7 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
/>
|
||||
</div>
|
||||
<div className='config-item config-item-bottom'>
|
||||
<span className=''>Hyphenation</span>
|
||||
<span className=''>{_('Hyphenation')}</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
className='toggle'
|
||||
@@ -147,12 +149,12 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
</div>
|
||||
|
||||
<div className='w-full'>
|
||||
<h2 className='mb-2 font-medium'>Page</h2>
|
||||
<h2 className='mb-2 font-medium'>{_('Page')}</h2>
|
||||
<div className='card bg-base-100 border-base-200 border shadow'>
|
||||
<div className='divide-base-200 divide-y'>
|
||||
<NumberInput
|
||||
className='config-item-top'
|
||||
label='Margins (px)'
|
||||
label={_('Margins (px)')}
|
||||
value={marginPx}
|
||||
onChange={setMarginPx}
|
||||
min={0}
|
||||
@@ -160,21 +162,21 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
step={4}
|
||||
/>
|
||||
<NumberInput
|
||||
label='Gaps (%)'
|
||||
label={_('Gaps (%)')}
|
||||
value={gapPercent}
|
||||
onChange={setGapPercent}
|
||||
min={0}
|
||||
max={30}
|
||||
/>
|
||||
<NumberInput
|
||||
label='Maximum Number of Columns'
|
||||
label={_('Maximum Number of Columns')}
|
||||
value={maxColumnCount}
|
||||
onChange={setMaxColumnCount}
|
||||
min={1}
|
||||
max={2}
|
||||
/>
|
||||
<NumberInput
|
||||
label='Maximum Inline Size'
|
||||
label={_('Maximum Inline Size')}
|
||||
value={maxInlineSize}
|
||||
onChange={setMaxInlineSize}
|
||||
min={500}
|
||||
@@ -182,7 +184,7 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
step={100}
|
||||
/>
|
||||
<NumberInput
|
||||
label='Maximum Block Size'
|
||||
label={_('Maximum Block Size')}
|
||||
value={maxBlockSize}
|
||||
onChange={setMaxBlockSize}
|
||||
min={500}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import cssbeautify from 'cssbeautify';
|
||||
import { getStyles } from '@/utils/style';
|
||||
import { useTheme } from '@/hooks/useTheme';
|
||||
@@ -9,6 +10,7 @@ const cssRegex =
|
||||
/((?:\s*)([\w#.@*,:\-.:>+~$$$$\"=(),*\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 (
|
||||
<div className='my-4 w-full space-y-6'>
|
||||
<div className='w-full'>
|
||||
<h2 className='mb-2 font-medium'>Animation</h2>
|
||||
<h2 className='mb-2 font-medium'>{_('Animation')}</h2>
|
||||
<div className='card bg-base-100 border shadow'>
|
||||
<div className='divide-y'>
|
||||
<div className='config-item config-item-top config-item-bottom'>
|
||||
<span className='text-gray-700'>Paging Animation</span>
|
||||
<span className='text-gray-700'>{_('Paging Animation')}</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
className='toggle'
|
||||
@@ -104,11 +106,11 @@ const MiscPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
</div>
|
||||
|
||||
<div className='w-full'>
|
||||
<h2 className='mb-2 font-medium'>Behavior</h2>
|
||||
<h2 className='mb-2 font-medium'>{_('Behavior')}</h2>
|
||||
<div className='card bg-base-100 border shadow'>
|
||||
<div className='divide-y'>
|
||||
<div className='config-item config-item-top config-item-bottom'>
|
||||
<span className='text-gray-700'>Disable Click-to-Flip</span>
|
||||
<span className='text-gray-700'>{_('Disable Click-to-Flip')}</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
className='toggle'
|
||||
@@ -121,7 +123,7 @@ const MiscPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
</div>
|
||||
|
||||
<div className='w-full'>
|
||||
<h2 className='mb-2 font-medium'>Custom CSS</h2>
|
||||
<h2 className='mb-2 font-medium'>{_('Custom CSS')}</h2>
|
||||
<div className={`card bg-base-100 border shadow ${error ? 'border-red-500' : ''}`}>
|
||||
<div className='divide-y'>
|
||||
<div className='css-text-area config-item-top config-item-bottom p-1'>
|
||||
|
||||
@@ -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<SettingsPanelType>('Font');
|
||||
const { setFontLayoutSettingsDialogOpen } = useSettingsStore();
|
||||
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
@@ -43,28 +47,28 @@ const SettingsDialog: React.FC<{ bookKey: string; config: BookConfig }> = ({ boo
|
||||
onClick={() => setActivePanel('Font')}
|
||||
>
|
||||
<RiFontSize size={20} className='mr-0' />
|
||||
Font
|
||||
{_('Font')}
|
||||
</button>
|
||||
<button
|
||||
className={`btn btn-ghost text-base-content h-8 min-h-8 px-4 ${activePanel === 'Layout' ? 'btn-active' : ''}`}
|
||||
onClick={() => setActivePanel('Layout')}
|
||||
>
|
||||
<RiDashboardLine size={20} className='mr-0' />
|
||||
Layout
|
||||
{_('Layout')}
|
||||
</button>
|
||||
<button
|
||||
className={`btn btn-ghost text-base-content h-8 min-h-8 px-4 ${activePanel === 'Color' ? 'btn-active' : ''}`}
|
||||
onClick={() => setActivePanel('Color')}
|
||||
>
|
||||
<VscSymbolColor size={20} className='mr-0' />
|
||||
Color
|
||||
{_('Color')}
|
||||
</button>
|
||||
<button
|
||||
className={`btn btn-ghost text-base-content h-8 min-h-8 px-4 ${activePanel === 'Misc' ? 'btn-active' : ''}`}
|
||||
onClick={() => setActivePanel('Misc')}
|
||||
>
|
||||
<IoAccessibilityOutline size={20} className='mr-0' />
|
||||
Misc
|
||||
{_('Misc')}
|
||||
</button>
|
||||
</div>
|
||||
<div className='flex h-full items-center justify-end'>
|
||||
|
||||
@@ -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<BookCardProps> = ({ cover, title, author }) => {
|
||||
const _ = useTranslation();
|
||||
return (
|
||||
<div className='flex h-20 w-full items-center'>
|
||||
<Image
|
||||
src={cover}
|
||||
alt='Book cover'
|
||||
alt={_('Book Cover')}
|
||||
width={56}
|
||||
height={80}
|
||||
className='mr-4 aspect-auto max-h-20 w-[15%] max-w-14 rounded-sm object-cover shadow-md'
|
||||
@@ -27,7 +29,7 @@ const BookCard: React.FC<BookCardProps> = ({ cover, title, author }) => {
|
||||
</div>
|
||||
<button
|
||||
className='btn btn-ghost hover:bg-base-300 h-6 min-h-6 w-6 rounded-full p-0 transition-colors'
|
||||
aria-label='More info'
|
||||
aria-label={_('More Info')}
|
||||
>
|
||||
<MdInfoOutline size={18} className='fill-base-content' />
|
||||
</button>
|
||||
|
||||
@@ -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<BookMenuProps> = ({ setIsDropdownOpen }) => {
|
||||
const _ = useTranslation();
|
||||
const { library } = useLibraryStore();
|
||||
const { openParallelView } = useBooksManager();
|
||||
const handleParallelView = (id: string) => {
|
||||
@@ -39,7 +41,7 @@ const BookMenu: React.FC<BookMenuProps> = ({ setIsDropdownOpen }) => {
|
||||
tabIndex={0}
|
||||
className='book-menu dropdown-content dropdown-center border-base-100 z-20 mt-3 w-60 shadow-2xl'
|
||||
>
|
||||
<MenuItem label='Parallel Read' noIcon>
|
||||
<MenuItem label={_('Parallel Read')} noIcon>
|
||||
<ul className='max-h-60 overflow-y-auto'>
|
||||
{library.slice(0, 20).map((book) => (
|
||||
<MenuItem
|
||||
@@ -62,10 +64,10 @@ const BookMenu: React.FC<BookMenuProps> = ({ setIsDropdownOpen }) => {
|
||||
))}
|
||||
</ul>
|
||||
</MenuItem>
|
||||
<MenuItem label='Reload Page' noIcon shortcut='Shift+R' onClick={handleReloadPage} />
|
||||
<MenuItem label={_('Reload Page')} noIcon shortcut='Shift+R' onClick={handleReloadPage} />
|
||||
<hr className='border-base-200 my-1' />
|
||||
{isWebApp && <MenuItem label='Download Readest' noIcon onClick={downloadReadest} />}
|
||||
<MenuItem label='About Readest' noIcon onClick={showAboutReadest} />
|
||||
<MenuItem label={_('About Readest')} noIcon onClick={showAboutReadest} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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<BooknoteItemProps> = ({ 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<BooknoteItemProps> = ({ bookKey, item, editable = f
|
||||
)}
|
||||
onClick={editNote.bind(null, item)}
|
||||
>
|
||||
<div className='align-bottom text-blue-400'>Edit</div>
|
||||
<div className='align-bottom text-blue-400'>{_('Edit')}</div>
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
@@ -125,7 +127,7 @@ const BooknoteItem: React.FC<BooknoteItemProps> = ({ bookKey, item, editable = f
|
||||
)}
|
||||
onClick={deleteNote.bind(null, item)}
|
||||
>
|
||||
<div className='align-bottom text-red-400'>Delete</div>
|
||||
<div className='align-bottom text-red-400'>{_('Delete')}</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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<SearchBarProps> = ({
|
||||
searchTerm: term,
|
||||
onSearchResultChange,
|
||||
}) => {
|
||||
const _ = useTranslation();
|
||||
const { envConfig } = useEnv();
|
||||
const { settings } = useSettingsStore();
|
||||
const { getConfig, saveConfig } = useBookDataStore();
|
||||
@@ -149,7 +151,7 @@ const SearchBar: React.FC<SearchBarProps> = ({
|
||||
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'
|
||||
/>
|
||||
|
||||
|
||||
@@ -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<SearchOptionsProps> = ({
|
||||
onSearchConfigChanged,
|
||||
setIsDropdownOpen,
|
||||
}) => {
|
||||
const _ = useTranslation();
|
||||
const handleSetScope = () => {
|
||||
onSearchConfigChanged({
|
||||
...searchConfig,
|
||||
@@ -46,7 +48,7 @@ const SearchOptions: React.FC<SearchOptionsProps> = ({
|
||||
<span style={{ minWidth: '20px' }}>
|
||||
{searchConfig.scope === 'book' && <MdCheck size={20} className='text-base-content' />}
|
||||
</span>
|
||||
<span className='ml-2'>Book</span>
|
||||
<span className='ml-2'>{_('Book')}</span>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -60,7 +62,7 @@ const SearchOptions: React.FC<SearchOptionsProps> = ({
|
||||
<MdCheck size={20} className='text-base-content' />
|
||||
)}
|
||||
</span>
|
||||
<span className='ml-2'>Chapter</span>
|
||||
<span className='ml-2'>{_('Chapter')}</span>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -74,7 +76,7 @@ const SearchOptions: React.FC<SearchOptionsProps> = ({
|
||||
<span style={{ minWidth: '20px' }}>
|
||||
{searchConfig.matchCase && <MdCheck size={20} className='text-base-content' />}
|
||||
</span>
|
||||
<span className='ml-2'>Match Case</span>
|
||||
<span className='ml-2'>{_('Match Case')}</span>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -86,7 +88,7 @@ const SearchOptions: React.FC<SearchOptionsProps> = ({
|
||||
<span style={{ minWidth: '20px' }}>
|
||||
{searchConfig.matchWholeWords && <MdCheck size={20} className='text-base-content' />}
|
||||
</span>
|
||||
<span className='ml-2'>Match Whole Words</span>
|
||||
<span className='ml-2'>{_('Match Whole Words')}</span>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -98,7 +100,7 @@ const SearchOptions: React.FC<SearchOptionsProps> = ({
|
||||
<span style={{ minWidth: '20px' }}>
|
||||
{searchConfig.matchDiacritics && <MdCheck size={20} className='text-base-content' />}
|
||||
</span>
|
||||
<span className='ml-2'>Match Diacritics</span>
|
||||
<span className='ml-2'>{_('Match Diacritics')}</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -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 (
|
||||
<dialog id='about_window' className='modal'>
|
||||
<form method='dialog' className='modal-box w-96 max-w-lg p-4'>
|
||||
@@ -30,7 +32,9 @@ export const AboutWindow = () => {
|
||||
</div>
|
||||
<h2 className='text-2xl font-bold'>Readest</h2>
|
||||
<p className='text-neutral-content text-sm'>Bilingify LLC</p>
|
||||
<span className='badge badge-primary mt-2'>Version {packageJson.version}</span>
|
||||
<span className='badge badge-primary mt-2'>
|
||||
{_('Version {{version}}', { version: packageJson.version })}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className='divider'></div>
|
||||
@@ -55,7 +59,7 @@ export const AboutWindow = () => {
|
||||
<p className='text-neutral-content mt-2 text-xs'>
|
||||
Source code is available at{' '}
|
||||
<a
|
||||
href='https://github.com/chrox/readest'
|
||||
href='https://github.com/readest/readest'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-blue-500 underline'
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
|
||||
const Alert: React.FC<{
|
||||
title: string;
|
||||
@@ -7,6 +8,7 @@ const Alert: React.FC<{
|
||||
onClickCancel: () => void;
|
||||
onClickConfirm: () => void;
|
||||
}> = ({ title, message, onClickCancel, onClickConfirm }) => {
|
||||
const _ = useTranslation();
|
||||
return (
|
||||
<div
|
||||
role='alert'
|
||||
@@ -37,10 +39,10 @@ const Alert: React.FC<{
|
||||
</div>
|
||||
<div className='flex space-x-2'>
|
||||
<button className='btn btn-sm' onClick={onClickCancel}>
|
||||
Cancel
|
||||
{_('Cancel')}
|
||||
</button>
|
||||
<button className='btn btn-sm btn-warning' onClick={onClickConfirm}>
|
||||
Confirm
|
||||
{_('Confirm')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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'
|
||||
>
|
||||
<span className='loading loading-dots loading-lg'></span>
|
||||
<span className='hidden'>Loading...</span>
|
||||
<span className='hidden'>{_('Loading...')}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
Generated
+593
-11
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user