Skip to content

Commit

Permalink
Delay parsing of translations until they're used
Browse files Browse the repository at this point in the history
While doing some profiling for #2900, I noticed that
`miniflux.app/v2/internal/locale.LoadCatalogMessages` is responsible for more
than 10% of the consumed memory. As most miniflux instances won't have enough
diverse users to use all the available translations at the same time, it
makes sense to load them on demand.

The overhead is a single function call and a check in a map, per call to
translation-related functions.

This should close #2975
  • Loading branch information
jvoisin committed Dec 8, 2024
1 parent c1ef986 commit b5e28b4
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 21 deletions.
5 changes: 0 additions & 5 deletions internal/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (

"miniflux.app/v2/internal/config"
"miniflux.app/v2/internal/database"
"miniflux.app/v2/internal/locale"
"miniflux.app/v2/internal/storage"
"miniflux.app/v2/internal/ui/static"
"miniflux.app/v2/internal/version"
Expand Down Expand Up @@ -153,10 +152,6 @@ func Parse() {
slog.Info("The default value for DATABASE_URL is used")
}

if err := locale.LoadCatalogMessages(); err != nil {
printErrorAndExit(fmt.Errorf("unable to load translations: %v", err))
}

if err := static.CalculateBinaryFileChecksums(); err != nil {
printErrorAndExit(fmt.Errorf("unable to calculate binary file checksums: %v", err))
}
Expand Down
13 changes: 11 additions & 2 deletions internal/locale/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,24 @@ import (
type translationDict map[string]interface{}
type catalog map[string]translationDict

var defaultCatalog catalog
var defaultCatalog = make(catalog, len(AvailableLanguages()))

//go:embed translations/*.json
var translationFiles embed.FS

func GetTranslationDict(language string) (translationDict, error) {
if _, ok := defaultCatalog[language]; !ok {
var err error
if defaultCatalog[language], err = loadTranslationFile(language); err != nil {
return nil, err
}
}
return defaultCatalog[language], nil
}

// LoadCatalogMessages loads and parses all translations encoded in JSON.
func LoadCatalogMessages() error {
var err error
defaultCatalog = make(catalog, len(AvailableLanguages()))

for language := range AvailableLanguages() {
defaultCatalog[language], err = loadTranslationFile(language)
Expand Down
33 changes: 19 additions & 14 deletions internal/locale/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,28 @@ type Printer struct {
}

func (p *Printer) Print(key string) string {
if str, ok := defaultCatalog[p.language][key]; ok {
if translation, ok := str.(string); ok {
return translation
if dict, err := GetTranslationDict(p.language); err == nil {
if str, ok := dict[key]; ok {
if translation, ok := str.(string); ok {
return translation
}
}
}
return key
}

// Printf is like fmt.Printf, but using language-specific formatting.
func (p *Printer) Printf(key string, args ...interface{}) string {
var translation string
translation := key

str, found := defaultCatalog[p.language][key]
if !found {
translation = key
} else {
var valid bool
translation, valid = str.(string)
if !valid {
translation = key
if dict, err := GetTranslationDict(p.language); err == nil {
str, found := dict[key]
if found {
var valid bool
translation, valid = str.(string)
if !valid {
translation = key
}
}
}

Expand All @@ -39,9 +41,12 @@ func (p *Printer) Printf(key string, args ...interface{}) string {

// Plural returns the translation of the given key by using the language plural form.
func (p *Printer) Plural(key string, n int, args ...interface{}) string {
choices, found := defaultCatalog[p.language][key]
dict, err := GetTranslationDict(p.language)
if err != nil {
return key
}

if found {
if choices, found := dict[key]; found {
var plurals []string

switch v := choices.(type) {
Expand Down

0 comments on commit b5e28b4

Please sign in to comment.