1
0
Fork 0
mirror of https://github.com/miniflux/v2.git synced 2025-06-27 16:36:00 +00:00

Use embed package for translations instead of generated files

Replace "go generate" with the new embed package.
This commit is contained in:
Frédéric Guillot 2021-02-16 22:58:44 -08:00 committed by fguillot
parent a352aff93b
commit 5d65a85bdb
8 changed files with 103 additions and 3996 deletions

View file

@ -10,6 +10,7 @@ import (
"miniflux.app/config" "miniflux.app/config"
"miniflux.app/database" "miniflux.app/database"
"miniflux.app/locale"
"miniflux.app/logger" "miniflux.app/logger"
"miniflux.app/storage" "miniflux.app/storage"
"miniflux.app/version" "miniflux.app/version"
@ -100,6 +101,11 @@ func Parse() {
logger.Info("The default value for DATABASE_URL is used") logger.Info("The default value for DATABASE_URL is used")
} }
logger.Debug("Loading translations...")
if err := locale.LoadCatalogMessages(); err != nil {
logger.Fatal("Unable to load translations: %v", err)
}
db, err := database.NewConnectionPool( db, err := database.NewConnectionPool(
config.Opts.DatabaseURL(), config.Opts.DatabaseURL(),
config.Opts.DatabaseMinConns(), config.Opts.DatabaseMinConns(),

View file

@ -216,5 +216,4 @@ func main() {
generateBundle("template/views.go", "template", "templateViewsMap", glob("template/html/*.html")) generateBundle("template/views.go", "template", "templateViewsMap", glob("template/html/*.html"))
generateBundle("template/common.go", "template", "templateCommonMap", glob("template/html/common/*.html")) generateBundle("template/common.go", "template", "templateCommonMap", glob("template/html/common/*.html"))
generateBundle("locale/translations.go", "locale", "translations", glob("locale/translations/*.json"))
} }

View file

@ -5,6 +5,7 @@
package locale // import "miniflux.app/locale" package locale // import "miniflux.app/locale"
import ( import (
"embed"
"encoding/json" "encoding/json"
"fmt" "fmt"
) )
@ -14,23 +15,41 @@ type catalog map[string]translationDict
var defaultCatalog catalog var defaultCatalog catalog
func init() { //go:embed translations/*.json
var translationFiles embed.FS
// LoadCatalogMessages loads and parses all translations encoded in JSON.
func LoadCatalogMessages() error {
var err error
defaultCatalog = make(catalog) defaultCatalog = make(catalog)
for language, data := range translations { for language := range AvailableLanguages() {
messages, err := parseTranslationDict(data) defaultCatalog[language], err = loadTranslationFile(language)
if err != nil { if err != nil {
panic(err) return err
} }
defaultCatalog[language] = messages
} }
return nil
} }
func parseTranslationDict(data string) (translationDict, error) { func loadTranslationFile(language string) (translationDict, error) {
var translations translationDict translationFileData, err := translationFiles.ReadFile(fmt.Sprintf("translations/%s.json", language))
if err := json.Unmarshal([]byte(data), &translations); err != nil { if err != nil {
return nil, fmt.Errorf("invalid translation file: %v", err) return nil, err
} }
return translations, nil
translationMessages, err := parseTranslationMessages(translationFileData)
if err != nil {
return nil, err
}
return translationMessages, nil
}
func parseTranslationMessages(data []byte) (translationDict, error) {
var translationMessages translationDict
if err := json.Unmarshal(data, &translationMessages); err != nil {
return nil, fmt.Errorf(`invalid translation file: %w`, err)
}
return translationMessages, nil
} }

View file

@ -7,14 +7,14 @@ package locale // import "miniflux.app/locale"
import "testing" import "testing"
func TestParserWithInvalidData(t *testing.T) { func TestParserWithInvalidData(t *testing.T) {
_, err := parseTranslationDict(`{`) _, err := parseTranslationMessages([]byte(`{`))
if err == nil { if err == nil {
t.Fatal(`An error should be returned when parsing invalid data`) t.Fatal(`An error should be returned when parsing invalid data`)
} }
} }
func TestParser(t *testing.T) { func TestParser(t *testing.T) {
translations, err := parseTranslationDict(`{"k": "v"}`) translations, err := parseTranslationMessages([]byte(`{"k": "v"}`))
if err != nil { if err != nil {
t.Fatalf(`Unexpected parsing error: %v`, err) t.Fatalf(`Unexpected parsing error: %v`, err)
} }
@ -32,3 +32,60 @@ func TestParser(t *testing.T) {
t.Fatal(`The translation key should contains the defined value`) t.Fatal(`The translation key should contains the defined value`)
} }
} }
func TestLoadCatalog(t *testing.T) {
if err := LoadCatalogMessages(); err != nil {
t.Fatal(err)
}
}
func TestAllKeysHaveValue(t *testing.T) {
for language := range AvailableLanguages() {
messages, err := loadTranslationFile(language)
if err != nil {
t.Fatalf(`Unable to load translation messages for language %q`, language)
}
if len(messages) == 0 {
t.Fatalf(`The language %q doesn't have any messages`, language)
}
for k, v := range messages {
switch value := v.(type) {
case string:
if value == "" {
t.Errorf(`The key %q for the language %q have an empty string as value`, k, language)
}
case []string:
if len(value) == 0 {
t.Errorf(`The key %q for the language %q have an empty list as value`, k, language)
}
}
}
}
}
func TestMissingTranslations(t *testing.T) {
refLang := "en_US"
references, err := loadTranslationFile(refLang)
if err != nil {
t.Fatal(`Unable to parse reference language`)
}
for language := range AvailableLanguages() {
if language == refLang {
continue
}
messages, err := loadTranslationFile(language)
if err != nil {
t.Fatalf(`Parsing error for language %q`, language)
}
for key := range references {
if _, found := messages[key]; !found {
t.Fatalf(`Translation key %q not found in language %q`, key, language)
}
}
}
}

View file

@ -8,12 +8,12 @@ import "testing"
func TestPluralRules(t *testing.T) { func TestPluralRules(t *testing.T) {
scenarios := map[string]map[int]int{ scenarios := map[string]map[int]int{
"default": map[int]int{ "default": {
1: 0, 1: 0,
2: 1, 2: 1,
5: 1, 5: 1,
}, },
"ar_AR": map[int]int{ "ar_AR": {
0: 0, 0: 0,
1: 1, 1: 1,
2: 2, 2: 2,
@ -21,32 +21,32 @@ func TestPluralRules(t *testing.T) {
11: 4, 11: 4,
200: 5, 200: 5,
}, },
"cs_CZ": map[int]int{ "cs_CZ": {
1: 0, 1: 0,
2: 1, 2: 1,
5: 2, 5: 2,
}, },
"pl_PL": map[int]int{ "pl_PL": {
1: 0, 1: 0,
2: 1, 2: 1,
5: 2, 5: 2,
}, },
"pt_BR": map[int]int{ "pt_BR": {
1: 0, 1: 0,
2: 1, 2: 1,
5: 1, 5: 1,
}, },
"ru_RU": map[int]int{ "ru_RU": {
1: 0, 1: 0,
2: 1, 2: 1,
5: 2, 5: 2,
}, },
"sr_RS": map[int]int{ "sr_RS": {
1: 0, 1: 0,
2: 1, 2: 1,
5: 2, 5: 2,
}, },
"zh_CN": map[int]int{ "zh_CN": {
1: 0, 1: 0,
5: 0, 5: 0,
}, },

File diff suppressed because it is too large Load diff

View file

@ -1,66 +0,0 @@
// Copyright 2018 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package locale // import "miniflux.app/locale"
import "testing"
func TestAllLanguagesHaveCatalog(t *testing.T) {
for language := range AvailableLanguages() {
if _, found := translations[language]; !found {
t.Fatalf(`This language do not have a catalog: %q`, language)
}
}
}
func TestAllKeysHaveValue(t *testing.T) {
for language := range AvailableLanguages() {
messages, err := parseTranslationDict(translations[language])
if err != nil {
t.Fatalf(`Parsing error for language %q`, language)
}
if len(messages) == 0 {
t.Fatalf(`The language %q doesn't have any messages`, language)
}
for k, v := range messages {
switch value := v.(type) {
case string:
if value == "" {
t.Errorf(`The key %q for the language %q have an empty string as value`, k, language)
}
case []string:
if len(value) == 0 {
t.Errorf(`The key %q for the language %q have an empty list as value`, k, language)
}
}
}
}
}
func TestMissingTranslations(t *testing.T) {
refLang := "en_US"
references, err := parseTranslationDict(translations[refLang])
if err != nil {
t.Fatal(`Unable to parse reference language`)
}
for language := range AvailableLanguages() {
if language == refLang {
continue
}
messages, err := parseTranslationDict(translations[language])
if err != nil {
t.Fatalf(`Parsing error for language %q`, language)
}
for key := range references {
if _, found := messages[key]; !found {
t.Fatalf(`Translation key %q not found in language %q`, key, language)
}
}
}
}

View file

@ -10,7 +10,6 @@ package main // import "miniflux.app"
//go:generate gofmt -s -w ui/static/js.go //go:generate gofmt -s -w ui/static/js.go
//go:generate gofmt -s -w template/views.go //go:generate gofmt -s -w template/views.go
//go:generate gofmt -s -w template/common.go //go:generate gofmt -s -w template/common.go
//go:generate gofmt -s -w locale/translations.go
import ( import (
"miniflux.app/cli" "miniflux.app/cli"