1
0
Fork 0
mirror of https://github.com/miniflux/v2.git synced 2025-08-11 17:51:01 +00:00

refactor(locale): introspect the translation files at load time

Since Go doesn't support unions, and because the translation format is a bit
wacky with the same field having multiple types, we must resort to
introspection to switch between single-item translation (for singular), and
multi-items ones (for plurals).

Previously, introspection was done at runtime, which is not only slow, but will
also only catch typing errors while trying to use the translations. The current
approach is to use a struct with a different field per possible type, and
implement a custom unmarshaller to dispatch the translations to the right one.
This should marginally reduce the memory consumption since interface-boxing
doesn't happen anymore, speed up the translations matching, and enforce proper
typing earlier. This also allows us to remove a bunch of now-useless tests.
This commit is contained in:
Julien Voisin 2025-08-01 04:10:14 +02:00 committed by GitHub
parent f3052eb8ed
commit 181e1341e1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 180 additions and 205 deletions

View file

@ -46,10 +46,14 @@ func TestLocalizedErrorWrapper_Translate(t *testing.T) {
// Set up test catalog
defaultCatalog = catalog{
"en_US": translationDict{
"error.test_key": "Error: %s (code: %d)",
singulars: map[string]string{
"error.test_key": "Error: %s (code: %d)",
},
},
"fr_FR": translationDict{
"error.test_key": "Erreur : %s (code : %d)",
singulars: map[string]string{
"error.test_key": "Erreur : %s (code : %d)",
},
},
}
@ -92,7 +96,9 @@ func TestLocalizedErrorWrapper_TranslateWithEmptyKey(t *testing.T) {
func TestLocalizedErrorWrapper_TranslateWithNoArgs(t *testing.T) {
defaultCatalog = catalog{
"en_US": translationDict{
"error.simple": "Simple error message",
singulars: map[string]string{
"error.simple": "Simple error message",
},
},
}
@ -128,7 +134,9 @@ func TestNewLocalizedError(t *testing.T) {
func TestLocalizedError_String(t *testing.T) {
defaultCatalog = catalog{
"en_US": translationDict{
"error.validation": "Validation failed for %s: %s",
singulars: map[string]string{
"error.validation": "Validation failed for %s: %s",
},
},
}
@ -158,7 +166,9 @@ func TestLocalizedError_StringWithMissingTranslation(t *testing.T) {
func TestLocalizedError_Error(t *testing.T) {
defaultCatalog = catalog{
"en_US": translationDict{
"error.database": "Database connection failed: %s",
singulars: map[string]string{
"error.database": "Database connection failed: %s",
},
},
}
@ -178,10 +188,14 @@ func TestLocalizedError_Error(t *testing.T) {
func TestLocalizedError_Translate(t *testing.T) {
defaultCatalog = catalog{
"en_US": translationDict{
"error.permission": "Permission denied for %s",
singulars: map[string]string{
"error.permission": "Permission denied for %s",
},
},
"es_ES": translationDict{
"error.permission": "Permiso denegado para %s",
singulars: map[string]string{
"error.permission": "Permiso denegado para %s",
},
},
}
@ -212,10 +226,14 @@ func TestLocalizedError_Translate(t *testing.T) {
func TestLocalizedError_TranslateWithNoArgs(t *testing.T) {
defaultCatalog = catalog{
"en_US": translationDict{
"error.generic": "An error occurred",
singulars: map[string]string{
"error.generic": "An error occurred",
},
},
"de_DE": translationDict{
"error.generic": "Ein Fehler ist aufgetreten",
singulars: map[string]string{
"error.generic": "Ein Fehler ist aufgetreten",
},
},
}
@ -239,7 +257,9 @@ func TestLocalizedError_TranslateWithNoArgs(t *testing.T) {
func TestLocalizedError_TranslateWithComplexArgs(t *testing.T) {
defaultCatalog = catalog{
"en_US": translationDict{
"error.complex": "Error %d: %s occurred at %s with severity %s",
singulars: map[string]string{
"error.complex": "Error %d: %s occurred at %s with severity %s",
},
},
}