chore: (#708) Print key validation errors, translate the language dialog
This commit is contained in:
parent
67a9d3b1d1
commit
217b17a058
|
|
@ -55,19 +55,19 @@
|
||||||
|
|
||||||
<dialog ref="languageDialog" class="language-dialog" @click="handleDialogClick">
|
<dialog ref="languageDialog" class="language-dialog" @click="handleDialogClick">
|
||||||
<div class="dialog-content" @click.stop>
|
<div class="dialog-content" @click.stop>
|
||||||
<h2>Select Language</h2>
|
<h2>{{ t('language-dialog.title') }}</h2>
|
||||||
<select v-model="selectedLanguage" @change="changeLanguage" class="language-select">
|
<select v-model="selectedLanguage" @change="changeLanguage" class="language-select">
|
||||||
<option v-for="(name, code) in availableLanguages" :key="code" :value="code">
|
<option v-for="(name, code) in availableLanguages" :key="code" :value="code">
|
||||||
{{ name }}
|
{{ name }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<p class="browser-languages">
|
<p class="browser-languages">
|
||||||
Browser languages:
|
{{ t('language-dialog.browser-languages') }}:
|
||||||
<span v-if="browserLanguages.length > 0">{{ browserLanguages.join(', ') }}</span>
|
<span v-if="browserLanguages.length > 0">{{ browserLanguages.join(', ') }}</span>
|
||||||
<span v-else>Not available</span>
|
<span v-else>{{ t('language-dialog.not-available') }}</span>
|
||||||
</p>
|
</p>
|
||||||
<div class="dialog-buttons">
|
<div class="dialog-buttons">
|
||||||
<button @click="closeLanguageDialog">Close</button>
|
<button @click="closeLanguageDialog">{{ t('language-dialog.close') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
|
||||||
|
|
@ -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"}}}
|
{"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"}}}
|
||||||
|
|
@ -17,4 +17,8 @@ translations:
|
||||||
logs.status: Status
|
logs.status: Status
|
||||||
logs.no-logs-to-display: Es gibt keine Protokolle zu anzeigen.
|
logs.no-logs-to-display: Es gibt keine Protokolle zu anzeigen.
|
||||||
return-to-index: Zurück zur Startseite
|
return-to-index: Zurück zur Startseite
|
||||||
search-filter: Filter aktuelle Seite
|
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
|
||||||
|
|
@ -17,4 +17,8 @@ translations:
|
||||||
logs.status: Status
|
logs.status: Status
|
||||||
logs.no-logs-to-display: There are no logs to display.
|
logs.no-logs-to-display: There are no logs to display.
|
||||||
return-to-index: Return to index
|
return-to-index: Return to index
|
||||||
search-filter: Filter current page
|
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
|
||||||
|
|
@ -17,4 +17,8 @@ translations:
|
||||||
logs.status: Status
|
logs.status: Status
|
||||||
logs.no-logs-to-display: No hay registros para mostrar.
|
logs.no-logs-to-display: No hay registros para mostrar.
|
||||||
return-to-index: Volver a la página principal
|
return-to-index: Volver a la página principal
|
||||||
search-filter: Filtrar página actual
|
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
|
||||||
|
|
@ -17,4 +17,8 @@ translations:
|
||||||
logs.status: Status
|
logs.status: Status
|
||||||
logs.no-logs-to-display: Non ci sono registri da mostrare.
|
logs.no-logs-to-display: Non ci sono registri da mostrare.
|
||||||
return-to-index: Torna alla pagina principale
|
return-to-index: Torna alla pagina principale
|
||||||
search-filter: Filtra la pagina corrente
|
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
|
||||||
63
lang/main.go
63
lang/main.go
|
|
@ -90,9 +90,72 @@ func getCombinedLanguageContent() *CombinedTranslationsOutput {
|
||||||
output.Messages[languageName] = yamlData.Translations
|
output.Messages[languageName] = yamlData.Translations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validateTranslations(output)
|
||||||
|
|
||||||
return 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 {
|
func filterLanguageFiles(files []os.DirEntry) []os.DirEntry {
|
||||||
ret := make([]os.DirEntry, 0)
|
ret := make([]os.DirEntry, 0)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,4 +17,8 @@ translations:
|
||||||
logs.status: 状态
|
logs.status: 状态
|
||||||
logs.no-logs-to-display: 没有日志可显示。
|
logs.no-logs-to-display: 没有日志可显示。
|
||||||
return-to-index: 返回首页
|
return-to-index: 返回首页
|
||||||
search-filter: 过滤当前页面
|
search-filter: 过滤当前页面
|
||||||
|
language-dialog.title: 选择语言
|
||||||
|
language-dialog.browser-languages: 浏览器语言
|
||||||
|
language-dialog.not-available: 不可用
|
||||||
|
language-dialog.close: 关闭
|
||||||
Loading…
Reference in New Issue