Ghidul complet pentru internaționalizarea Go
De la fișierele de mesaje la determinarea sigură pentru goroutine a setării regionale: configurați internaționalizarea aplicației Go cu go-i18n, apoi automatizați traducerile cu IA.
Instalați go-i18n
go-i18n este cea mai populară bibliotecă de internaționalizare pentru Go. Utilizează reguli de plural CLDR și șabloane Go pentru interpolarea variabilelor și acceptă fișiere de mesaje JSON, TOML și YAML. Pentru asocierea etichetelor de limbă aveți nevoie și de golang.org/x/text.
go get -u github.com/nicksnyder/go-i18n/v2/i18n
go get -u golang.org/x/text/languageCreați fișierele de mesaje
Creați câte un fișier JSON pentru fiecare limbă într-un director locales. Fiecare mesaj are un ID și una sau mai multe forme de plural. Go-i18n utilizează sintaxa șabloanelor Go (acolade duble cu un punct ca prefix) pentru interpolarea variabilelor.
{
"HelloWorld": { "other": "Hello, World!" },
"Greeting": { "other": "Hello, {{.Name}}!" },
"ItemCount": {
"one": "{{.Count}} item",
"other": "{{.Count}} items"
},
"WelcomeBack": {
"other": "Welcome back, {{.Name}}. You have {{.Count}} messages."
}
}Încărcați Bundle
Bundle este registrul central al go-i18n. Creați unul la pornire, înregistrați formatul fișierului și încărcați toate fișierele de mesaje. Bundle poate fi utilizat în siguranță de goroutine — creați-l o singură dată și partajați-l în întreaga aplicație.
package main
import (
"encoding/json"
"fmt"
"github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/text/language"
)
func main() {
// 1. Create a bundle with a default language
bundle := i18n.NewBundle(language.English)
// 2. Register the unmarshal function for your file format
bundle.RegisterUnmarshalFunc("json", json.Unmarshal)
// 3. Load message files
bundle.MustLoadMessageFile("locales/en.json")
bundle.MustLoadMessageFile("locales/ja.json")
bundle.MustLoadMessageFile("locales/de.json")
// 4. Create a localizer and localize a message
localizer := i18n.NewLocalizer(bundle, "ja")
msg := localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "HelloWorld",
})
fmt.Println(msg) // "こんにちは、世界!"
}Utilizați Localizer
Creați câte un Localizer pentru fiecare solicitare, folosind limba preferată a utilizatorului. Localizer identifică mesajele din Bundle, gestionează redarea șabloanelor cu motorul text/template din Go și selectează forma corectă de plural pe baza PluralCount.
// Simple message
msg := localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "HelloWorld",
})
// Message with template data
msg := localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "Greeting",
TemplateData: map[string]interface{}{
"Name": "Alice",
},
})
// "Hello, Alice!" (en) or "こんにちは、Aliceさん!" (ja)
// Plural + template data
msg := localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "ItemCount",
PluralCount: 5,
TemplateData: map[string]interface{}{
"Count": 5,
},
})
// "5 items" (en) or "5個のアイテム" (ja)
// Combined: plurals + multiple variables
msg := localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "WelcomeBack",
TemplateData: map[string]interface{}{
"Name": "Alice",
"Count": 3,
},
})func handler(w http.ResponseWriter, r *http.Request) {
// Accept-Language: ja,en;q=0.9,de;q=0.8
accept := r.Header.Get("Accept-Language")
// NewLocalizer accepts multiple languages — first match wins
localizer := i18n.NewLocalizer(bundle, accept)
msg := localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "HelloWorld",
})
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Write([]byte(msg))
}Gestionați regulile de plural
go-i18n implementează regulile de plural CLDR pentru toate limbile. Engleza are 2 forme (one, other). Araba are 6 (zero, one, two, few, many, other). Japoneza are 1 (other). Definiți toate formele necesare în fișierele de mesaje — go-i18n o selectează pe cea corectă pe baza PluralCount.
// English: 2 forms (one, other)
{
"ItemCount": {
"one": "{{.Count}} item",
"other": "{{.Count}} items"
}
}
// Arabic: 6 forms (zero, one, two, few, many, other)
{
"ItemCount": {
"zero": "لا عناصر",
"one": "عنصر واحد",
"two": "عنصران",
"few": "{{.Count}} عناصر",
"many": "{{.Count}} عنصرًا",
"other": "{{.Count}} عنصر"
}
}
// Japanese: 1 form (other)
{
"ItemCount": {
"other": "{{.Count}}個のアイテム"
}
}// go-i18n selects the correct plural form based on PluralCount
localizer := i18n.NewLocalizer(bundle, "ar")
msg := localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "ItemCount",
PluralCount: 3,
TemplateData: map[string]interface{}{
"Count": 3,
},
})
// Arabic "few" form: "3 عناصر"
msg = localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "ItemCount",
PluralCount: 1,
TemplateData: map[string]interface{}{
"Count": 1,
},
})
// Arabic "one" form: "عنصر واحد"Detectarea setării regionale
În aplicațiile web, detectați limba preferată a utilizatorului din mai multe surse: parametri de interogare, module cookie, antetul Accept-Language sau segmentele căii URL. Utilizați golang.org/x/text/language.Matcher pentru negocierea limbii conformă cu BCP 47.
// detectLocale resolves the user's preferred language.
// Priority: query param > cookie > Accept-Language header > default
func detectLocale(r *http.Request, matcher language.Matcher) string {
// 1. Explicit query parameter: ?lang=ja
if lang := r.URL.Query().Get("lang"); lang != "" {
tag, _, _ := matcher.Match(language.Make(lang))
return tag.String()
}
// 2. Cookie from previous selection
if cookie, err := r.Cookie("lang"); err == nil {
tag, _, _ := matcher.Match(language.Make(cookie.Value))
return tag.String()
}
// 3. Accept-Language header
accept := r.Header.Get("Accept-Language")
if accept != "" {
tags, _, _ := language.ParseAcceptLanguage(accept)
if len(tags) > 0 {
tag, _, _ := matcher.Match(tags...)
return tag.String()
}
}
return "en" // 4. Default
}
// Usage:
matcher := language.NewMatcher([]language.Tag{
language.English, language.Japanese,
language.German, language.Spanish,
})
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
locale := detectLocale(r, matcher)
localizer := i18n.NewLocalizer(bundle, locale)
// ... use localizer
})Corectați rezerva pentru fiecare cheie cu go-locale-chain
go-i18n are o limitare cunoscută: după asocierea unei setări regionale care conține cel puțin o traducere, cheile lipsă nu sunt căutate în următoarea setare regională din lanț. Un utilizator pt-BR cu un fișier pt-BR tradus parțial primește șiruri goale în loc să se utilizeze pt-PT sau pt ca rezervă. go-locale-chain remediază problema prin determinarea rezervei pentru fiecare cheie în 75 de lanțuri integrate de setări regionale.
go get github.com/i18n-agent/go-locale-chainpackage main
import (
"encoding/json"
"fmt"
"github.com/nicksnyder/go-i18n/v2/i18n"
localechain "github.com/i18n-agent/go-locale-chain"
"golang.org/x/text/language"
)
func main() {
// 1. Configure fallback chains (call once at startup)
localechain.Configure()
// 2. Set up go-i18n bundle as usual
bundle := i18n.NewBundle(language.English)
bundle.RegisterUnmarshalFunc("json", json.Unmarshal)
bundle.MustLoadMessageFile("locales/en.json")
bundle.MustLoadMessageFile("locales/pt.json")
bundle.MustLoadMessageFile("locales/pt-PT.json")
bundle.MustLoadMessageFile("locales/pt-BR.json")
// 3. Resolve with per-key fallback
result, _ := localechain.ResolveWithLoader("pt-BR", func(locale string) (map[string]string, error) {
localizer := i18n.NewLocalizer(bundle, locale)
messages := make(map[string]string)
for _, id := range []string{"hello", "goodbye", "thanks"} {
msg, err := localizer.Localize(&i18n.LocalizeConfig{MessageID: id})
if err == nil {
messages[id] = msg
}
}
return messages, nil
})
fmt.Println(result["hello"]) // "Olá (BR)" — from pt-BR
fmt.Println(result["goodbye"]) // "Adeus (PT)" — fallback to pt-PT
fmt.Println(result["thanks"]) // "Obrigado" — fallback to pt
}// Standalone: zero external dependencies, works with any format
localechain.Configure()
result, _ := localechain.ResolveWithLoader("es-MX", func(locale string) (map[string]string, error) {
data, err := os.ReadFile(fmt.Sprintf("locales/%s.json", locale))
if err != nil {
return nil, err // Locale file doesn't exist — skip
}
var msgs map[string]string
json.Unmarshal(data, &msgs)
return msgs, nil
})
// es-MX -> es-419 -> es: each key resolved from most specific localeAutomatizați traducerile
După finalizarea configurării i18n, traduceți fișierele de localizare cu ajutorul IA. Generați traduceri pentru toate limbile-țintă din fișierul-sursă în engleză — direct din IDE sau în fluxul CI/CD.
# In your IDE, ask your AI assistant:
> Translate locales/en.json to German, Japanese, and Spanish
✓ locales/de.json created (1.2s)
✓ locales/ja.json created (1.5s)
✓ locales/es.json created (1.1s)
# Or use the CLI in CI/CD:
npx i18n-agent translate locales/en.json --lang de,ja,esAutomatizați controlul calității traducerilor
Probleme frecvente
PluralCount și TemplateData nu corespund
RegisterUnmarshalFunc lipsește
Rezerva pentru fiecare cheie nu funcționează
Sintaxa șablonului: {'{.Var}'}, nu {'{Var}'}
Structura recomandată a fișierelor
my-go-app/
├── locales/
│ ├── en.json # Source language (English)
│ ├── de.json # German translations
│ ├── ja.json # Japanese translations
│ ├── es.json # Spanish translations
│ ├── pt.json # Portuguese (base)
│ ├── pt-PT.json # Portuguese (Portugal)
│ └── pt-BR.json # Portuguese (Brazil)
├── i18n/
│ ├── bundle.go # Bundle initialization
│ ├── detect.go # Locale detection logic
│ └── middleware.go # HTTP middleware for locale
├── main.go
├── go.mod
└── go.sumÎncercați acum i18n Agent
Plasați aici fișierul de traducere
JSON, YAML, PO, XML, CSV, Markdown, Properties
sau faceți clic pentru a-l selecta
Limbi țintă
Mecanism de rezervă pentru setările regionale cu go-locale-chain
Atunci când lipsește o cheie de traducere dintr-o setare regională precum pt-BR, go-i18n revine direct la limba implicită în loc să verifice mai întâi setarea regională părinte pt.
go get github.com/i18n-agent/go-locale-chainimport localechain "github.com/i18n-agent/go-locale-chain"
chain := localechain.New(localechain.Config{
Fallbacks: map[string][]string{
"pt-BR": {"pt", "en"},
"zh-Hant-HK": {"zh-Hant", "zh", "en"},
},
})Consultați Ghidul nostru privind mecanismele de rezervă pentru setările regionale, care conține lista completă a platformelor acceptate și cele 75 de lanțuri integrate. Learn more →