From dbef7ef98b780d9e811cd0bebce1f8d1eb399b21 Mon Sep 17 00:00:00 2001 From: hugo Date: Sat, 21 Feb 2026 12:58:34 +0100 Subject: [PATCH] chore: more i18n, will it ever end? --- .audit/i18n-candidates.txt | 9 ++++ src/renderer/components/Editor/Editor.tsx | 65 +++++++++++++++-------- src/renderer/i18n/locales/de.json | 20 +++++++ src/renderer/i18n/locales/en.json | 20 +++++++ src/renderer/i18n/locales/es.json | 20 +++++++ src/renderer/i18n/locales/fr.json | 20 +++++++ src/renderer/i18n/locales/it.json | 20 +++++++ 7 files changed, 151 insertions(+), 23 deletions(-) create mode 100644 .audit/i18n-candidates.txt diff --git a/.audit/i18n-candidates.txt b/.audit/i18n-candidates.txt new file mode 100644 index 0000000..0aa1104 --- /dev/null +++ b/.audit/i18n-candidates.txt @@ -0,0 +1,9 @@ +## JSX text nodes (tsx) + +## UI props with literal text + +## Dialogs/prompts/alerts/confirms + +## Toasts and notifications with literals + +## Main-process menu/dialog labels diff --git a/src/renderer/components/Editor/Editor.tsx b/src/renderer/components/Editor/Editor.tsx index 34c2abc..2d421c6 100644 --- a/src/renderer/components/Editor/Editor.tsx +++ b/src/renderer/components/Editor/Editor.tsx @@ -1453,8 +1453,6 @@ const formatBytes = (bytes: number): string => { return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]; }; -const MONTH_NAMES = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; - interface DashboardStats { totalPosts: number; draftCount: number; @@ -1479,6 +1477,7 @@ interface TagDataWithColor { } const Dashboard: React.FC = () => { + const { t: tr, language } = useI18n(); const { posts, media } = useAppStore(); const [stats, setStats] = useState(null); const [yearMonthData, setYearMonthData] = useState<{ year: number; month: number; count: number }[]>([]); @@ -1486,6 +1485,12 @@ const Dashboard: React.FC = () => { const [tagColors, setTagColors] = useState>(new Map()); const [categoryCounts, setCategoryCounts] = useState([]); + const uiDateLocale = UI_DATE_LOCALE[language] || UI_DATE_LOCALE.en; + const monthFormatter = useMemo( + () => new Intl.DateTimeFormat(uiDateLocale, { month: 'short' }), + [uiDateLocale] + ); + useEffect(() => { const loadStats = async () => { try { @@ -1553,49 +1558,63 @@ const Dashboard: React.FC = () => { const displayPublishedCount = stats?.publishedCount ?? 0; const displayArchivedCount = stats?.archivedCount ?? 0; + const getPostCountLabel = useCallback((count: number) => { + return tr(count === 1 ? 'dashboard.postCount.one' : 'dashboard.postCount.other', { count }); + }, [tr]); + + const getPostStatusLabel = useCallback((status: string) => { + const statusKeyByValue: Record = { + draft: 'dashboard.status.draft', + published: 'dashboard.status.published', + archived: 'dashboard.status.archived', + }; + const key = statusKeyByValue[status]; + return key ? tr(key) : status; + }, [tr]); + return (
-

Dashboard

-

Overview of your blog database

+

{tr('dashboard.title')}

+

{tr('dashboard.subtitle')}

{displayTotalPosts}
-
Total Posts
+
{tr('dashboard.stats.totalPosts')}
- {displayPublishedCount} published - {displayDraftCount} drafts - {displayArchivedCount > 0 && {displayArchivedCount} archived} + {tr('dashboard.stats.published', { count: displayPublishedCount })} + {tr('dashboard.stats.drafts', { count: displayDraftCount })} + {displayArchivedCount > 0 && {tr('dashboard.stats.archived', { count: displayArchivedCount })}}
{media.length}
-
Media Files
+
{tr('dashboard.stats.mediaFiles')}
- {imageCount} images + {tr('dashboard.stats.images', { count: imageCount })} {formatBytes(totalMediaSize)}
{tagCounts.length}
-
Tags
+
{tr('dashboard.stats.tags')}
- {categoryCounts.length} categories + {tr('dashboard.stats.categories', { count: categoryCounts.length })}
{timelineEntries.length > 0 && (
-

Posts Over Time

+

{tr('dashboard.section.postsOverTime')}

{timelineEntries.map((entry) => (
{entry.count}
-
{MONTH_NAMES[entry.month]}
+
{monthFormatter.format(new Date(entry.year, entry.month, 1))}
))}
@@ -1604,7 +1623,7 @@ const Dashboard: React.FC = () => { {tagCloudItems.length > 0 && (
-

Tags

+

{tr('dashboard.section.tags')}

{tagCloudItems.map(item => { const hasColor = !!item.color; @@ -1620,26 +1639,26 @@ const Dashboard: React.FC = () => { key={item.tag} className={`dashboard-tag ${hasColor ? 'has-color' : ''}`} style={style} - title={`${item.count} post${item.count !== 1 ? 's' : ''}`} + title={getPostCountLabel(item.count)} > {item.tag} ); })} - {tagCounts.length > 40 && +{tagCounts.length - 40} more} + {tagCounts.length > 40 && {tr('dashboard.tagCloud.more', { count: tagCounts.length - 40 })}}
)} {categoryCounts.length > 0 && (
-

Categories

+

{tr('dashboard.section.categories')}

{categoryCounts.map(cat => ( {cat.category} {cat.count} @@ -1650,7 +1669,7 @@ const Dashboard: React.FC = () => { {recentPosts.length > 0 && (
-

Recently Updated

+

{tr('dashboard.section.recentlyUpdated')}

{recentPosts.map(post => (
{ useAppStore.getState().openTab({ type: 'post', id: post.id, isTransient: false }); }} > - {post.title || 'Untitled'} - {post.status} - {new Date(post.updatedAt).toLocaleDateString()} + {post.title || tr('editor.untitled')} + {getPostStatusLabel(post.status)} + {new Date(post.updatedAt).toLocaleDateString(uiDateLocale)}
))}
diff --git a/src/renderer/i18n/locales/de.json b/src/renderer/i18n/locales/de.json index 297574d..32e9398 100644 --- a/src/renderer/i18n/locales/de.json +++ b/src/renderer/i18n/locales/de.json @@ -411,6 +411,26 @@ "editor.footer.created": "Erstellt", "editor.footer.updated": "Aktualisiert", "editor.footer.published": "Veröffentlicht", + "dashboard.title": "Übersicht", + "dashboard.subtitle": "Überblick über deine Blog-Datenbank", + "dashboard.stats.totalPosts": "Beiträge gesamt", + "dashboard.stats.published": "{count} veröffentlicht", + "dashboard.stats.drafts": "{count} Entwürfe", + "dashboard.stats.archived": "{count} archiviert", + "dashboard.stats.mediaFiles": "Mediendateien", + "dashboard.stats.images": "{count} Bilder", + "dashboard.stats.tags": "Schlagwörter", + "dashboard.stats.categories": "{count} Kategorien", + "dashboard.section.postsOverTime": "Beiträge im Zeitverlauf", + "dashboard.section.tags": "Schlagwörter", + "dashboard.section.categories": "Kategorien", + "dashboard.section.recentlyUpdated": "Kürzlich aktualisiert", + "dashboard.tagCloud.more": "+{count} weitere", + "dashboard.postCount.one": "{count} Beitrag", + "dashboard.postCount.other": "{count} Beiträge", + "dashboard.status.draft": "Entwurf", + "dashboard.status.published": "Veröffentlicht", + "dashboard.status.archived": "Archiviert", "projectSelector.switchProject": "Projekt wechseln", "projectSelector.selectProject": "Projekt auswählen", "projectSelector.projectsHeader": "Projekte", diff --git a/src/renderer/i18n/locales/en.json b/src/renderer/i18n/locales/en.json index b0aa638..162ebee 100644 --- a/src/renderer/i18n/locales/en.json +++ b/src/renderer/i18n/locales/en.json @@ -411,6 +411,26 @@ "editor.footer.created": "Created", "editor.footer.updated": "Updated", "editor.footer.published": "Published", + "dashboard.title": "Dashboard", + "dashboard.subtitle": "Overview of your blog database", + "dashboard.stats.totalPosts": "Total Posts", + "dashboard.stats.published": "{count} published", + "dashboard.stats.drafts": "{count} drafts", + "dashboard.stats.archived": "{count} archived", + "dashboard.stats.mediaFiles": "Media Files", + "dashboard.stats.images": "{count} images", + "dashboard.stats.tags": "Tags", + "dashboard.stats.categories": "{count} categories", + "dashboard.section.postsOverTime": "Posts Over Time", + "dashboard.section.tags": "Tags", + "dashboard.section.categories": "Categories", + "dashboard.section.recentlyUpdated": "Recently Updated", + "dashboard.tagCloud.more": "+{count} more", + "dashboard.postCount.one": "{count} post", + "dashboard.postCount.other": "{count} posts", + "dashboard.status.draft": "Draft", + "dashboard.status.published": "Published", + "dashboard.status.archived": "Archived", "projectSelector.switchProject": "Switch project", "projectSelector.selectProject": "Select project", "projectSelector.projectsHeader": "Projects", diff --git a/src/renderer/i18n/locales/es.json b/src/renderer/i18n/locales/es.json index 12c7fe3..9a6167d 100644 --- a/src/renderer/i18n/locales/es.json +++ b/src/renderer/i18n/locales/es.json @@ -411,6 +411,26 @@ "editor.footer.created": "Creado", "editor.footer.updated": "Actualizado", "editor.footer.published": "Publicado", + "dashboard.title": "Panel", + "dashboard.subtitle": "Resumen de la base de datos de tu blog", + "dashboard.stats.totalPosts": "Entradas totales", + "dashboard.stats.published": "{count} publicadas", + "dashboard.stats.drafts": "{count} borradores", + "dashboard.stats.archived": "{count} archivadas", + "dashboard.stats.mediaFiles": "Archivos multimedia", + "dashboard.stats.images": "{count} imágenes", + "dashboard.stats.tags": "Etiquetas", + "dashboard.stats.categories": "{count} categorías", + "dashboard.section.postsOverTime": "Entradas a lo largo del tiempo", + "dashboard.section.tags": "Etiquetas", + "dashboard.section.categories": "Categorías", + "dashboard.section.recentlyUpdated": "Actualizadas recientemente", + "dashboard.tagCloud.more": "+{count} más", + "dashboard.postCount.one": "{count} entrada", + "dashboard.postCount.other": "{count} entradas", + "dashboard.status.draft": "Borrador", + "dashboard.status.published": "Publicada", + "dashboard.status.archived": "Archivada", "projectSelector.switchProject": "Cambiar proyecto", "projectSelector.selectProject": "Seleccionar proyecto", "projectSelector.projectsHeader": "Proyectos", diff --git a/src/renderer/i18n/locales/fr.json b/src/renderer/i18n/locales/fr.json index 479ce97..9fa5d19 100644 --- a/src/renderer/i18n/locales/fr.json +++ b/src/renderer/i18n/locales/fr.json @@ -411,6 +411,26 @@ "editor.footer.created": "Créé", "editor.footer.updated": "Mis à jour", "editor.footer.published": "Publié", + "dashboard.title": "Tableau de bord", + "dashboard.subtitle": "Aperçu de la base de données de votre blog", + "dashboard.stats.totalPosts": "Articles au total", + "dashboard.stats.published": "{count} publiés", + "dashboard.stats.drafts": "{count} brouillons", + "dashboard.stats.archived": "{count} archivés", + "dashboard.stats.mediaFiles": "Fichiers média", + "dashboard.stats.images": "{count} images", + "dashboard.stats.tags": "Étiquettes", + "dashboard.stats.categories": "{count} catégories", + "dashboard.section.postsOverTime": "Articles dans le temps", + "dashboard.section.tags": "Étiquettes", + "dashboard.section.categories": "Catégories", + "dashboard.section.recentlyUpdated": "Récemment mis à jour", + "dashboard.tagCloud.more": "+{count} de plus", + "dashboard.postCount.one": "{count} article", + "dashboard.postCount.other": "{count} articles", + "dashboard.status.draft": "Brouillon", + "dashboard.status.published": "Publié", + "dashboard.status.archived": "Archivé", "projectSelector.switchProject": "Changer de projet", "projectSelector.selectProject": "Sélectionner un projet", "projectSelector.projectsHeader": "Projets", diff --git a/src/renderer/i18n/locales/it.json b/src/renderer/i18n/locales/it.json index 4a87bf5..0eab75f 100644 --- a/src/renderer/i18n/locales/it.json +++ b/src/renderer/i18n/locales/it.json @@ -411,6 +411,26 @@ "editor.footer.created": "Creato", "editor.footer.updated": "Aggiornato", "editor.footer.published": "Pubblicato", + "dashboard.title": "Dashboard", + "dashboard.subtitle": "Panoramica del database del tuo blog", + "dashboard.stats.totalPosts": "Post totali", + "dashboard.stats.published": "{count} pubblicati", + "dashboard.stats.drafts": "{count} bozze", + "dashboard.stats.archived": "{count} archiviati", + "dashboard.stats.mediaFiles": "File multimediali", + "dashboard.stats.images": "{count} immagini", + "dashboard.stats.tags": "Tag", + "dashboard.stats.categories": "{count} categorie", + "dashboard.section.postsOverTime": "Post nel tempo", + "dashboard.section.tags": "Tag", + "dashboard.section.categories": "Categorie", + "dashboard.section.recentlyUpdated": "Aggiornati di recente", + "dashboard.tagCloud.more": "+{count} in più", + "dashboard.postCount.one": "{count} post", + "dashboard.postCount.other": "{count} post", + "dashboard.status.draft": "Bozza", + "dashboard.status.published": "Pubblicato", + "dashboard.status.archived": "Archiviato", "projectSelector.switchProject": "Cambia progetto", "projectSelector.selectProject": "Seleziona progetto", "projectSelector.projectsHeader": "Progetti",