i18n API

i18n

package

API reference for the i18n package.

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

localeFS
defaultDomain
string
locale
string

Returns

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!"))