diff --git a/frontend/resources/vue/App.vue b/frontend/resources/vue/App.vue index f170735..01a2b6d 100644 --- a/frontend/resources/vue/App.vue +++ b/frontend/resources/vue/App.vue @@ -55,19 +55,19 @@
-

Select Language

+

{{ t('language-dialog.title') }}

- Browser languages: + {{ t('language-dialog.browser-languages') }}: {{ browserLanguages.join(', ') }} - Not available + {{ t('language-dialog.not-available') }}

- +
diff --git a/lang/combined_output.json b/lang/combined_output.json index e7cd1df..cc90e3b 100644 --- a/lang/combined_output.json +++ b/lang/combined_output.json @@ -1 +1 @@ -{"messages":{"de-DE":{"connected":"Verbunden","docs":"Dokumentation","login-button":"Login","logs.action":"Aktion","logs.metadata":"Metadaten","logs.no-logs-to-display":"Es gibt keine Protokolle zu anzeigen.","logs.page-description":"Dies ist eine Liste von Protokollen von Aktionen, die ausgeführt wurden. Sie können die Liste nach Aktionstitel filtern.","logs.status":"Status","logs.timestamp":"Zeitstempel","logs.title":"Protokolle","nav.actions":"Aktionen","nav.diagnostics":"Diagnostik","nav.entities":"Entitäten","nav.logs":"Protokolle","raise-issue":"Ein Problem melden auf GitHub","return-to-index":"Zurück zur Startseite","search-filter":"Filter aktuelle Seite","welcome":"Willkommen bei OliveTin"},"en":{"connected":"Connected","docs":"Documentation","login-button":"Login","logs.action":"Action","logs.metadata":"Metadata","logs.no-logs-to-display":"There are no logs to display.","logs.page-description":"This is a list of logs from actions that have been executed. You can filter the list by action title.","logs.status":"Status","logs.timestamp":"Timestamp","logs.title":"Logs","nav.actions":"Actions","nav.diagnostics":"Diagnostics","nav.entities":"Entities","nav.logs":"Logs","raise-issue":"Raise an issue on GitHub","return-to-index":"Return to index","search-filter":"Filter current page","welcome":"Welcome to OliveTin"},"es-ES":{"connected":"Conectado","docs":"Documentación","login-button":"Iniciar sesión","logs.action":"Acción","logs.metadata":"Metadatos","logs.no-logs-to-display":"No hay registros para mostrar.","logs.page-description":"Esta es una lista de registros de acciones que han sido ejecutadas. Puede filtrar la lista por título de acción.","logs.status":"Status","logs.timestamp":"Timestamp","logs.title":"Registros","nav.actions":"Acciones","nav.diagnostics":"Diagnósticos","nav.entities":"Entidades","nav.logs":"Registros","raise-issue":"Reportar un problema en GitHub","return-to-index":"Volver a la página principal","search-filter":"Filtrar página actual","welcome":"Bienvenido a OliveTin"},"it-IT":{"connected":"Connesso","docs":"Documentazione","login-button":"Login","logs.action":"Azione","logs.metadata":"Metadati","logs.no-logs-to-display":"Non ci sono registri da mostrare.","logs.page-description":"Questa è una lista di registri delle azioni che sono state eseguite. Puoi filtrare la lista per titolo dell'azione.","logs.status":"Status","logs.timestamp":"Timestamp","logs.title":"Registri","logs.user":"Utente","nav.actions":"Azioni","nav.diagnostics":"Diagnostica","nav.entities":"Entità","nav.logs":"Registri","raise-issue":"Segnala un problema su GitHub","return-to-index":"Torna alla pagina principale","search-filter":"Filtra la pagina corrente","welcome":"Benvenuto in OliveTin"},"zh-Hans-CN":{"connected":"已连接","docs":"文档","login-button":"登录","logs.action":"动作","logs.metadata":"元数据","logs.no-logs-to-display":"没有日志可显示。","logs.page-description":"这是一个动作执行日志列表。您可以按动作标题过滤列表。","logs.status":"状态","logs.timestamp":"时间戳","logs.title":"日志","nav.actions":"动作","nav.diagnostics":"诊断","nav.entities":"实体","nav.logs":"日志","raise-issue":"报告问题 on GitHub","return-to-index":"返回首页","search-filter":"过滤当前页面","welcome":"欢迎使用 OliveTin"}}} \ No newline at end of file +{"messages":{"de-DE":{"connected":"Verbunden","docs":"Dokumentation","language-dialog.browser-languages":"Browser-Sprachen","language-dialog.close":"Schließen","language-dialog.not-available":"Nicht verfügbar","language-dialog.title":"Sprache auswählen","login-button":"Login","logs.action":"Aktion","logs.metadata":"Metadaten","logs.no-logs-to-display":"Es gibt keine Protokolle zu anzeigen.","logs.page-description":"Dies ist eine Liste von Protokollen von Aktionen, die ausgeführt wurden. Sie können die Liste nach Aktionstitel filtern.","logs.status":"Status","logs.timestamp":"Zeitstempel","logs.title":"Protokolle","nav.actions":"Aktionen","nav.diagnostics":"Diagnostik","nav.entities":"Entitäten","nav.logs":"Protokolle","raise-issue":"Ein Problem melden auf GitHub","return-to-index":"Zurück zur Startseite","search-filter":"Filter aktuelle Seite","welcome":"Willkommen bei OliveTin"},"en":{"connected":"Connected","docs":"Documentation","language-dialog.browser-languages":"Browser languages","language-dialog.close":"Close","language-dialog.not-available":"Not available","language-dialog.title":"Select Language","login-button":"Login","logs.action":"Action","logs.metadata":"Metadata","logs.no-logs-to-display":"There are no logs to display.","logs.page-description":"This is a list of logs from actions that have been executed. You can filter the list by action title.","logs.status":"Status","logs.timestamp":"Timestamp","logs.title":"Logs","nav.actions":"Actions","nav.diagnostics":"Diagnostics","nav.entities":"Entities","nav.logs":"Logs","raise-issue":"Raise an issue on GitHub","return-to-index":"Return to index","search-filter":"Filter current page","welcome":"Welcome to OliveTin"},"es-ES":{"connected":"Conectado","docs":"Documentación","language-dialog.browser-languages":"Idiomas del navegador","language-dialog.close":"Cerrar","language-dialog.not-available":"No disponible","language-dialog.title":"Seleccionar idioma","login-button":"Iniciar sesión","logs.action":"Acción","logs.metadata":"Metadatos","logs.no-logs-to-display":"No hay registros para mostrar.","logs.page-description":"Esta es una lista de registros de acciones que han sido ejecutadas. Puede filtrar la lista por título de acción.","logs.status":"Status","logs.timestamp":"Timestamp","logs.title":"Registros","nav.actions":"Acciones","nav.diagnostics":"Diagnósticos","nav.entities":"Entidades","nav.logs":"Registros","raise-issue":"Reportar un problema en GitHub","return-to-index":"Volver a la página principal","search-filter":"Filtrar página actual","welcome":"Bienvenido a OliveTin"},"it-IT":{"connected":"Connesso","docs":"Documentazione","language-dialog.browser-languages":"Lingue del browser","language-dialog.close":"Chiudi","language-dialog.not-available":"Non disponibile","language-dialog.title":"Seleziona lingua","login-button":"Login","logs.action":"Azione","logs.metadata":"Metadati","logs.no-logs-to-display":"Non ci sono registri da mostrare.","logs.page-description":"Questa è una lista di registri delle azioni che sono state eseguite. Puoi filtrare la lista per titolo dell'azione.","logs.status":"Status","logs.timestamp":"Timestamp","logs.title":"Registri","nav.actions":"Azioni","nav.diagnostics":"Diagnostica","nav.entities":"Entità","nav.logs":"Registri","raise-issue":"Segnala un problema su GitHub","return-to-index":"Torna alla pagina principale","search-filter":"Filtra la pagina corrente","welcome":"Benvenuto in OliveTin"},"zh-Hans-CN":{"connected":"已连接","docs":"文档","language-dialog.browser-languages":"浏览器语言","language-dialog.close":"关闭","language-dialog.not-available":"不可用","language-dialog.title":"选择语言","login-button":"登录","logs.action":"动作","logs.metadata":"元数据","logs.no-logs-to-display":"没有日志可显示。","logs.page-description":"这是一个动作执行日志列表。您可以按动作标题过滤列表。","logs.status":"状态","logs.timestamp":"时间戳","logs.title":"日志","nav.actions":"动作","nav.diagnostics":"诊断","nav.entities":"实体","nav.logs":"日志","raise-issue":"在 GitHub 上报告问题","return-to-index":"返回首页","search-filter":"过滤当前页面","welcome":"欢迎使用 OliveTin"}}} \ No newline at end of file diff --git a/lang/de-DE.yaml b/lang/de-DE.yaml index ad7ec6e..52962dc 100644 --- a/lang/de-DE.yaml +++ b/lang/de-DE.yaml @@ -17,4 +17,8 @@ translations: logs.status: Status logs.no-logs-to-display: Es gibt keine Protokolle zu anzeigen. return-to-index: Zurück zur Startseite - search-filter: Filter aktuelle Seite \ No newline at end of file + search-filter: Filter aktuelle Seite + language-dialog.title: Sprache auswählen + language-dialog.browser-languages: Browser-Sprachen + language-dialog.not-available: Nicht verfügbar + language-dialog.close: Schließen \ No newline at end of file diff --git a/lang/en.yaml b/lang/en.yaml index 2e80a56..7020935 100644 --- a/lang/en.yaml +++ b/lang/en.yaml @@ -17,4 +17,8 @@ translations: logs.status: Status logs.no-logs-to-display: There are no logs to display. return-to-index: Return to index - search-filter: Filter current page \ No newline at end of file + search-filter: Filter current page + language-dialog.title: Select Language + language-dialog.browser-languages: Browser languages + language-dialog.not-available: Not available + language-dialog.close: Close \ No newline at end of file diff --git a/lang/es-ES.yaml b/lang/es-ES.yaml index 72b28a4..19e7f15 100644 --- a/lang/es-ES.yaml +++ b/lang/es-ES.yaml @@ -17,4 +17,8 @@ translations: logs.status: Status logs.no-logs-to-display: No hay registros para mostrar. return-to-index: Volver a la página principal - search-filter: Filtrar página actual \ No newline at end of file + search-filter: Filtrar página actual + language-dialog.title: Seleccionar idioma + language-dialog.browser-languages: Idiomas del navegador + language-dialog.not-available: No disponible + language-dialog.close: Cerrar \ No newline at end of file diff --git a/lang/it-IT.yaml b/lang/it-IT.yaml index a9e057e..2ac7512 100644 --- a/lang/it-IT.yaml +++ b/lang/it-IT.yaml @@ -17,4 +17,8 @@ translations: logs.status: Status logs.no-logs-to-display: Non ci sono registri da mostrare. return-to-index: Torna alla pagina principale - search-filter: Filtra la pagina corrente \ No newline at end of file + search-filter: Filtra la pagina corrente + language-dialog.title: Seleziona lingua + language-dialog.browser-languages: Lingue del browser + language-dialog.not-available: Non disponibile + language-dialog.close: Chiudi \ No newline at end of file diff --git a/lang/main.go b/lang/main.go index c22745a..d8bd039 100644 --- a/lang/main.go +++ b/lang/main.go @@ -90,9 +90,72 @@ func getCombinedLanguageContent() *CombinedTranslationsOutput { output.Messages[languageName] = yamlData.Translations } + validateTranslations(output) + return output } +// getReferenceKeys returns the keys from the "en" translation as the reference set. +func getReferenceKeys(messages map[string]map[string]string) map[string]bool { + enTranslations, exists := messages["en"] + if !exists { + return nil + } + + referenceKeys := make(map[string]bool, len(enTranslations)) + for key := range enTranslations { + referenceKeys[key] = true + } + return referenceKeys +} + +// findMissingKeys returns the keys that are in referenceKeys but not in translations. +func findMissingKeys(referenceKeys map[string]bool, translations map[string]string) []string { + missing := make([]string, 0) + for key := range referenceKeys { + if _, exists := translations[key]; !exists { + missing = append(missing, key) + } + } + return missing +} + +// findExtraKeys returns the keys that are in translations but not in referenceKeys. +func findExtraKeys(referenceKeys map[string]bool, translations map[string]string) []string { + extra := make([]string, 0) + for key := range translations { + if !referenceKeys[key] { + extra = append(extra, key) + } + } + return extra +} + +// validateTranslations checks all translations against the "en" reference and prints warnings for missing and extra keys. +func validateTranslations(output *CombinedTranslationsOutput) { + referenceKeys := getReferenceKeys(output.Messages) + if referenceKeys == nil { + log.Warnf("No 'en' translation found, skipping validation") + return + } + + for langName, translations := range output.Messages { + if langName == "en" { + continue + } + + missing := findMissingKeys(referenceKeys, translations) + if len(missing) > 0 { + log.Warnf("Translation '%s' is missing %d key(s): %v", langName, len(missing), missing) + } + + extra := findExtraKeys(referenceKeys, translations) + if len(extra) > 0 { + log.Warnf("Translation '%s' has %d extra key(s) not in 'en': %v", langName, len(extra), extra) + } + } +} + func filterLanguageFiles(files []os.DirEntry) []os.DirEntry { ret := make([]os.DirEntry, 0) diff --git a/lang/zh-Hans-CN.yaml b/lang/zh-Hans-CN.yaml index b3b9fac..c97377e 100644 --- a/lang/zh-Hans-CN.yaml +++ b/lang/zh-Hans-CN.yaml @@ -17,4 +17,8 @@ translations: logs.status: 状态 logs.no-logs-to-display: 没有日志可显示。 return-to-index: 返回首页 - search-filter: 过滤当前页面 \ No newline at end of file + search-filter: 过滤当前页面 + language-dialog.title: 选择语言 + language-dialog.browser-languages: 浏览器语言 + language-dialog.not-available: 不可用 + language-dialog.close: 关闭 \ No newline at end of file