authelia/cmd/authelia-gen/cmd_locales.go

216 lines
4.7 KiB
Go

package main
import (
"encoding/json"
"fmt"
"io/fs"
"os"
"path/filepath"
"sort"
"strings"
"github.com/spf13/cobra"
"golang.org/x/text/language"
"golang.org/x/text/language/display"
"github.com/authelia/authelia/v4/internal/utils"
)
func newLocalesCmd() *cobra.Command {
cmd := &cobra.Command{
Use: cmdUseLocales,
Short: "Generate locales files",
RunE: localesRunE,
DisableAutoGenTag: true,
}
return cmd
}
func localesRunE(cmd *cobra.Command, args []string) (err error) {
var (
root, pathLocales string
pathWebI18NIndex, pathDocsDataLanguages string
)
if root, err = cmd.Flags().GetString(cmdFlagRoot); err != nil {
return err
}
if pathLocales, err = cmd.Flags().GetString(cmdFlagDirLocales); err != nil {
return err
}
if pathWebI18NIndex, err = cmd.Flags().GetString(cmdFlagFileWebI18N); err != nil {
return err
}
if pathDocsDataLanguages, err = cmd.Flags().GetString(cmdFlagDocsDataLanguages); err != nil {
return err
}
data, err := getLanguages(filepath.Join(root, pathLocales))
if err != nil {
return err
}
fullPathWebI18NIndex := filepath.Join(root, pathWebI18NIndex)
var (
f *os.File
dataJSON []byte
)
if f, err = os.Create(fullPathWebI18NIndex); err != nil {
return fmt.Errorf("failed to create file '%s': %w", fullPathWebI18NIndex, err)
}
if err = tmplWebI18NIndex.Execute(f, data); err != nil {
return err
}
if dataJSON, err = json.Marshal(data); err != nil {
return err
}
fullPathDocsDataLanguages := filepath.Join(root, pathDocsDataLanguages)
if err = os.WriteFile(fullPathDocsDataLanguages, dataJSON, 0600); err != nil {
return fmt.Errorf("failed to write file '%s': %w", fullPathDocsDataLanguages, err)
}
return nil
}
//nolint:gocyclo
func getLanguages(dir string) (languages *Languages, err error) {
//nolint:prealloc
var locales []string
languages = &Languages{
Defaults: DefaultsLanguages{
Namespace: localeNamespaceDefault,
},
}
var defaultTag language.Tag
if defaultTag, err = language.Parse(localeDefault); err != nil {
return nil, fmt.Errorf("failed to parse default language: %w", err)
}
languages.Defaults.Language = Language{
Display: display.English.Tags().Name(defaultTag),
Locale: localeDefault,
}
if err = filepath.Walk(dir, func(path string, info fs.FileInfo, errWalk error) (err error) {
if errWalk != nil {
return errWalk
}
nameLower := strings.ToLower(info.Name())
ext := filepath.Ext(nameLower)
ns := strings.Replace(nameLower, ext, "", 1)
if ext != ".json" {
return nil
}
if !utils.IsStringInSlice(ns, languages.Namespaces) {
languages.Namespaces = append(languages.Namespaces, ns)
}
fdir, _ := filepath.Split(path)
locale := filepath.Base(fdir)
if utils.IsStringInSlice(locale, locales) {
for i, l := range languages.Languages {
if l.Locale == locale {
if utils.IsStringInSlice(ns, languages.Languages[i].Namespaces) {
break
}
languages.Languages[i].Namespaces = append(languages.Languages[i].Namespaces, ns)
break
}
}
return nil
}
var localeReal string
parts := strings.SplitN(locale, "-", 2)
if len(parts) == 2 && strings.EqualFold(parts[0], parts[1]) {
localeReal = parts[0]
} else {
localeReal = locale
}
var tag language.Tag
if tag, err = language.Parse(localeReal); err != nil {
return fmt.Errorf("failed to parse language '%s': %w", localeReal, err)
}
l := Language{
Display: display.English.Tags().Name(tag),
Locale: localeReal,
Namespaces: []string{ns},
Fallbacks: []string{languages.Defaults.Language.Locale},
Tag: tag,
}
languages.Languages = append(languages.Languages, l)
locales = append(locales, l.Locale)
return nil
}); err != nil {
return nil, err
}
var langs []Language //nolint:prealloc
for i, lang := range languages.Languages {
p := lang.Tag.Parent()
if p.String() == "und" || strings.Contains(p.String(), "-") {
continue
}
if utils.IsStringInSlice(p.String(), locales) {
continue
}
if p.String() != lang.Locale {
lang.Fallbacks = append([]string{p.String()}, lang.Fallbacks...)
}
languages.Languages[i] = lang
l := Language{
Display: display.English.Tags().Name(p),
Locale: p.String(),
Namespaces: lang.Namespaces,
Fallbacks: []string{languages.Defaults.Language.Locale},
Tag: p,
}
langs = append(langs, l)
locales = append(locales, l.Locale)
}
languages.Languages = append(languages.Languages, langs...)
sort.Slice(languages.Languages, func(i, j int) bool {
return languages.Languages[i].Locale == localeDefault || languages.Languages[i].Locale < languages.Languages[j].Locale
})
return languages, nil
}