i18n
API
i18n
packageAPI reference for the i18n
package.
Imports
(9)
F
function
CheckMissingStrings
CheckMissingStrings scans the rootPath for translation calls (e.g., .Trans(“KEY”))
and verifies they exist in the provided locale file (PO format).
It returns a map where the key is the file path and the value is a slice of missing keys.
Parameters
rootPath
string
localeFile
string
Returns
map[string][]string
error
pkg/v1/i18n/check.go:35-113
func CheckMissingStrings(rootPath string, localeFile string) (map[string][]string, error)
{
localeData, err := os.Open(localeFile)
if err != nil {
return nil, fmt.Errorf("failed to open locale file: %w", err)
}
defer localeData.Close()
definedKeys := make(map[string]bool)
scanner := bufio.NewScanner(localeData)
msgidRe := regexp.MustCompile(`^msgid "(.+)"$`)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if strings.HasPrefix(line, "msgid \"") {
matches := msgidRe.FindStringSubmatch(line)
if len(matches) > 1 {
definedKeys[matches[1]] = true
}
}
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("error reading locale file: %w", err)
}
sourceRe := regexp.MustCompile(`\.Trans\("([\S.]+)"`)
prRe := regexp.MustCompile(`pr:([\w\.]+)`)
missing := make(map[string][]string)
err = filepath.WalkDir(rootPath, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
if d.Name() == ".git" || d.Name() == "vendor" {
return filepath.SkipDir
}
return nil
}
if !strings.HasSuffix(d.Name(), ".go") {
return nil
}
content, err := os.ReadFile(path)
if err != nil {
return nil
}
matches := sourceRe.FindAllStringSubmatch(string(content), -1)
matches = append(matches, prRe.FindAllStringSubmatch(string(content), -1)...)
for _, match := range matches {
if len(match) < 2 {
continue
}
key := match[1]
if !definedKeys[key] {
seen := false
for _, k := range missing[path] {
if k == key {
seen = true
break
}
}
if !seen {
missing[path] = append(missing[path], key)
}
}
}
return nil
})
if err != nil {
return nil, err
}
return missing, nil
}
Example
missing, err := i18n.CheckMissingStrings(".", "locales/en/messages.po")
if err != nil {
log.Fatal(err)
}
for file, keys := range missing {
fmt.Printf("File %s has missing keys: %v\n", file, keys)
}
F
function
NewLocalizer
NewLocalizer creates a new localizer for the application, the localizer is
used to localize strings in the application. The localizer requires the
application and the locale to be passed in, the locale is the language
the user wants to use. If the locale is not found or is empty, the
localizer will default to English, assuming it as the fallback.
Parameters
Returns
error
pkg/v1/i18n/i18n.go:35-75
func NewLocalizer(localeFS fs.FS, defaultDomain string, locale string) (*spreak.Localizer, error)
{
foundLocale, err := language.Parse(locale)
if err != nil {
foundLocale = language.English
}
// we need to get the supported languages from the locales file system
// to do so we expect a LINGUAS file to be present
linguas, err := fs.ReadFile(localeFS, "LINGUAS")
if err != nil {
return nil, fmt.Errorf("no LINGUAS file found: %v", err)
}
// spreak.WithLanguage requires a slice of interfaces
supportedLanguages := make([]interface{}, 0)
for _, l := range strings.Split(string(linguas), "\n") {
if l == "" {
continue
}
supportedLanguages = append(supportedLanguages, language.MustParse(l))
}
// we need to create a new bundle for the localizer, here we use the RDNN
// as the default localizer domain
bundle, err := spreak.NewBundle(
spreak.WithSourceLanguage(language.MustParse("qaa")),
spreak.WithDefaultDomain(defaultDomain),
spreak.WithFilesystemLoader(defaultDomain,
spreak.WithFs(localeFS),
spreak.WithPoDecoder(),
spreak.WithMoDecoder(),
),
spreak.WithRequiredLanguage(foundLocale),
spreak.WithLanguage(supportedLanguages...),
)
if err != nil {
return nil, err
}
return spreak.NewLocalizer(bundle, foundLocale), nil
}
Example
t, err := i18n.NewLocalizer(app, "")
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Println(t.Get("I am Batman!"))
fmt.Println(t.Get("I am Batman!"))