Ο πλήρης οδηγός διεθνοποίησης για Go
Από τα αρχεία μηνυμάτων έως την ασφαλή για goroutines επιλογή γλώσσας: ρυθμίστε το i18n στην εφαρμογή Go με το go-i18n και αυτοματοποιήστε τις μεταφράσεις με AI.
Εγκαταστήστε το go-i18n
Το go-i18n είναι η δημοφιλέστερη βιβλιοθήκη διεθνοποίησης για Go. Χρησιμοποιεί κανόνες πληθυντικού CLDR, πρότυπα Go για παρεμβολή μεταβλητών και υποστηρίζει αρχεία μηνυμάτων JSON, TOML και YAML. Χρειάζεστε επίσης το golang.org/x/text για την αντιστοίχιση γλωσσικών ετικετών.
go get -u github.com/nicksnyder/go-i18n/v2/i18n
go get -u golang.org/x/text/languageΔημιουργήστε αρχεία μηνυμάτων
Δημιουργήστε ένα αρχείο JSON ανά γλώσσα σε έναν κατάλογο locales. Κάθε μήνυμα έχει ένα ID και μία ή περισσότερες μορφές πληθυντικού. Το go-i18n χρησιμοποιεί σύνταξη προτύπων Go, με διπλά άγκιστρα και πρόθεμα τελείας, για την παρεμβολή μεταβλητών.
{
"HelloWorld": { "other": "Hello, World!" },
"Greeting": { "other": "Hello, {{.Name}}!" },
"ItemCount": {
"one": "{{.Count}} item",
"other": "{{.Count}} items"
},
"WelcomeBack": {
"other": "Welcome back, {{.Name}}. You have {{.Count}} messages."
}
}Φορτώστε το Bundle
Το Bundle είναι το κεντρικό μητρώο του go-i18n. Δημιουργήστε το κατά την εκκίνηση, καταχωρίστε τη μορφή αρχείων και φορτώστε όλα τα αρχεία μηνυμάτων. Το Bundle είναι ασφαλές για goroutines — δημιουργήστε το μία φορά και χρησιμοποιήστε το σε ολόκληρη την εφαρμογή.
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) // "こんにちは、世界!"
}Χρησιμοποιήστε το Localizer
Δημιουργήστε ένα Localizer για κάθε αίτημα με την προτιμώμενη γλώσσα του χρήστη. Το Localizer επιλέγει μηνύματα από το Bundle, αποδίδει πρότυπα με τη μηχανή text/template της Go και επιλέγει τη σωστή μορφή πληθυντικού βάσει του 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))
}Χειριστείτε τους κανόνες πληθυντικού
Το go-i18n υλοποιεί κανόνες πληθυντικού CLDR για όλες τις γλώσσες. Τα Αγγλικά έχουν 2 μορφές (one, other). Τα Αραβικά έχουν 6 (zero, one, two, few, many, other). Τα Ιαπωνικά έχουν 1 (other). Ορίστε όλες τις απαιτούμενες μορφές στα αρχεία μηνυμάτων — το go-i18n επιλέγει τη σωστή βάσει του 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: "عنصر واحد"Εντοπίστε τη γλώσσα
Στις εφαρμογές Web, εντοπίστε την προτιμώμενη γλώσσα του χρήστη από πολλές πηγές: παραμέτρους ερωτήματος, cookies, την κεφαλίδα Accept-Language ή τμήματα διαδρομής URL. Χρησιμοποιήστε το golang.org/x/text/language.Matcher για γλωσσική διαπραγμάτευση συμβατή με το 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
})Διορθώστε την εναλλακτική επιλογή ανά κλειδί με το go-locale-chain
Το go-i18n έχει έναν γνωστό περιορισμό: μόλις αντιστοιχιστεί μια γλώσσα, δηλαδή υπάρχουν φορτωμένες μεταφράσεις γι’ αυτήν, τα κλειδιά που λείπουν δεν αναζητούνται στην επόμενη γλώσσα της αλυσίδας. Ένας χρήστης με γλώσσα pt-BR και μερικώς μεταφρασμένο αρχείο pt-BR λαμβάνει κενές συμβολοσειρές αντί να χρησιμοποιείται εναλλακτικά το pt-PT ή το pt. Το go-locale-chain το διορθώνει με εναλλακτική επιλογή ανά κλειδί σε 75 ενσωματωμένες αλυσίδες γλωσσών.
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 localeΑυτοματοποιήστε τις μεταφράσεις
Αφού ολοκληρώσετε τη ρύθμιση i18n, μεταφράστε τα αρχεία γλωσσών με AI. Δημιουργήστε μεταφράσεις για όλες τις γλώσσες-στόχους από το αρχικό αγγλικό αρχείο — απευθείας από το IDE ή μέσα στη διοχέτευση 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,esΑυτοματοποιήστε τον έλεγχο ποιότητας των μεταφράσεων
Συνηθισμένες παγίδες
Ασυμφωνία PluralCount και TemplateData
Λείπει το RegisterUnmarshalFunc
Η εναλλακτική επιλογή ανά κλειδί δεν λειτουργεί
Σύνταξη προτύπου: {'{.Var}'} και όχι {'{Var}'}
Προτεινόμενη δομή αρχείων
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Δοκιμάστε τώρα το i18n Agent
Αφήστε εδώ το αρχείο μετάφρασής σας
JSON, YAML, PO, XML, CSV, Markdown, Properties
ή κάντε κλικ για να επιλέξετε αρχείο
Γλώσσες-στόχοι
Εναλλακτική επιλογή γλώσσας με το go-locale-chain
Όταν λείπει ένα κλειδί μετάφρασης σε μια περιφερειακή γλώσσα όπως το pt-BR, το go-i18n μεταβαίνει απευθείας στην προεπιλεγμένη γλώσσα αντί να ελέγξει πρώτα τη γονική γλώσσα 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"},
},
})Δείτε τον οδηγό μας για την εναλλακτική επιλογή γλώσσας, με την πλήρη λίστα των υποστηριζόμενων framework και 75 ενσωματωμένων αλυσίδων. Learn more →