git-lfs/tr/tr.go
brian m. carlson 24213cfb93
tr: add basic support for localization
We'd like to support localizing Git LFS.  We have the gotext package,
which supports several different ways of getting GNU gettext-compatible
locale strings.  However, we need some central message catalog we can
use.

Let's create a singleton by the name of Tr.  That means that we can
translate a string by writing something like this:

  fmt.Println(tr.Tr.Get("This is a message about %s.", subject))

These strings can be automatically extracted by the xgotext tool
available from the package
github.com/leonelquinteros/gotext/cli/xgotext.  While currently quite
slow, it does understand Go syntax, unlike the standard GNU gettext
suite.

We initialize it based on the locale.  Since Go does not use the
standard C library, we have to emulate its behavior, as outlined in
locale(7).  If our locale is "en_DK.UTF-8", we first look for "en_DK"
and then "en", in that order.  This preserves a fallback for languages
which are similar across most speakers, like English and Spanish, and
can share a translation, but for locales which cannot, such pt_PT and
pt_BR, or zh_TW and zh_CN, this ensures we prefer a more appropriate
locale.

Introduce a variable called "locales" which will be used to store
Base64-encoded MO files (compiled Gettext files) for each locale.  We
can still load external locales from the standard directory
(/usr/share/locale), but this preserves the behavior of providing a
single, relocatable binary, which people like.  If this becomes a
problem in the future, we can revisit it.  Population of this variable
will come in a future commit.
2021-11-10 14:03:53 +00:00

60 lines
1.2 KiB
Go

package tr
import (
"encoding/base64"
"os"
"strings"
"github.com/leonelquinteros/gotext"
)
//go:generate go run ../tr/trgen/trgen.go
var Tr = gotext.NewLocale("/usr/share/locale", "en")
var locales = make(map[string]string)
func findLocale() string {
vars := []string{"LC_ALL", "LC_MESSAGES", "LANG"}
for _, varname := range vars {
if val, ok := os.LookupEnv(varname); ok {
return val
}
}
return ""
}
func processLocale(locale string) []string {
options := make([]string, 0, 2)
// For example, split "en_DK.UTF-8" into "en_DK" and "UTF-8".
pieces := strings.Split(locale, ".")
options = append(options, pieces[0])
// For example, split "en_DK" into "en" and "DK".
pieces = strings.Split(pieces[0], "_")
if len(pieces) > 1 {
options = append(options, pieces[0])
}
return options
}
func InitializeLocale() {
locale := findLocale()
if len(locale) == 0 {
return
}
Tr = gotext.NewLocale("/usr/share/locale", locale)
Tr.AddDomain("git-lfs")
for _, loc := range processLocale(locale) {
if moData, ok := locales[loc]; ok {
mo := gotext.NewMo()
decodedData, err := base64.StdEncoding.DecodeString(moData)
if err != nil {
continue
}
mo.Parse(decodedData)
Tr.AddTranslator("git-lfs", mo)
return
}
}
}