camper/pkg/locale/locale.go

132 lines
2.7 KiB
Go

/*
* SPDX-FileCopyrightText: 2023 jordi fita mas <jfita@peritasoft.com>
* SPDX-License-Identifier: AGPL-3.0-only
*/
package locale
import (
"context"
"github.com/leonelquinteros/gotext"
"golang.org/x/text/language"
"dev.tandem.ws/tandem/camper/pkg/database"
)
type Locale struct {
*gotext.Locale
CurrencyPattern string
Language language.Tag
Endonym string
}
type Locales map[language.Tag]*Locale
func (m Locales) Tags() []language.Tag {
keys := make([]language.Tag, len(m))
i := 0
for k := range m {
keys[i] = k
i++
}
return keys
}
func (m Locales) Get(lang string) (loc *Locale, ok bool) {
tag, err := language.Parse(lang)
if err != nil {
return
}
loc, ok = m[tag]
return
}
func GetAll(ctx context.Context, db *database.DB) (Locales, error) {
availableLanguages, err := getAvailableLanguages(ctx, db)
if err != nil {
return nil, err
}
locales := Locales{}
for _, lang := range availableLanguages {
locale := lang.locale()
locale.AddDomain("camper")
locales[lang.tag] = locale
}
return locales, nil
}
func (l *Locale) Gettext(str string) string {
return l.GetD(l.GetDomain(), str)
}
func (l *Locale) Pgettext(str string, ctx string) string {
return l.GetDC(l.GetDomain(), str, ctx)
}
func (l *Locale) GettextNoop(str string) string {
return str
}
func PgettextNoop(str string, ctx string) string {
return str
}
func Match(acceptLanguage string, locales Locales, matcher language.Matcher) *Locale {
t, _, err := language.ParseAcceptLanguage(acceptLanguage)
if err != nil {
return nil
}
var locale *Locale
tag, _, confidence := matcher.Match(t...)
if confidence > language.No {
var ok bool
locale, ok = locales[tag]
for !ok && !tag.IsRoot() {
tag = tag.Parent()
locale, ok = locales[tag]
}
}
return locale
}
type availableLanguage struct {
tag language.Tag
endonym string
currencyPattern string
}
func getAvailableLanguages(ctx context.Context, db *database.DB) ([]*availableLanguage, error) {
rows, err := db.Query(ctx, "select lang_tag, endonym, currency_pattern from language where selectable")
if err != nil {
return nil, err
}
defer rows.Close()
var languages []*availableLanguage
for rows.Next() {
lang := &availableLanguage{}
var langTag string
err = rows.Scan(&langTag, &lang.endonym, &lang.currencyPattern)
if err != nil {
return nil, err
}
lang.tag = language.MustParse(langTag)
languages = append(languages, lang)
}
if rows.Err() != nil {
return nil, rows.Err()
}
return languages, nil
}
func (lang *availableLanguage) locale() *Locale {
return &Locale{
gotext.NewLocale("locale", lang.tag.String()),
lang.currencyPattern,
lang.tag,
lang.endonym,
}
}