Skip to main content

Ο πλήρης οδηγός διεθνοποίησης για Go

Από τα αρχεία μηνυμάτων έως την ασφαλή για goroutines επιλογή γλώσσας: ρυθμίστε το i18n στην εφαρμογή Go με το go-i18n και αυτοματοποιήστε τις μεταφράσεις με AI.

1

Εγκαταστήστε το go-i18n

Το go-i18n είναι η δημοφιλέστερη βιβλιοθήκη διεθνοποίησης για Go. Χρησιμοποιεί κανόνες πληθυντικού CLDR, πρότυπα Go για παρεμβολή μεταβλητών και υποστηρίζει αρχεία μηνυμάτων JSON, TOML και YAML. Χρειάζεστε επίσης το golang.org/x/text για την αντιστοίχιση γλωσσικών ετικετών.

Το go-i18n v2 απαιτεί Go 1.16+. Το πακέτο golang.org/x/text παρέχει ανάλυση και αντιστοίχιση γλωσσικών ετικετών BCP 47, τις οποίες χρησιμοποιεί εσωτερικά το go-i18n για την επιλογή κανόνων πληθυντικού.
Terminal
go get -u github.com/nicksnyder/go-i18n/v2/i18n
go get -u golang.org/x/text/language
2

Δημιουργήστε αρχεία μηνυμάτων

Δημιουργήστε ένα αρχείο JSON ανά γλώσσα σε έναν κατάλογο locales. Κάθε μήνυμα έχει ένα ID και μία ή περισσότερες μορφές πληθυντικού. Το go-i18n χρησιμοποιεί σύνταξη προτύπων Go, με διπλά άγκιστρα και πρόθεμα τελείας, για την παρεμβολή μεταβλητών.

locales/en.json
{
  "HelloWorld": { "other": "Hello, World!" },
  "Greeting": { "other": "Hello, {{.Name}}!" },
  "ItemCount": {
    "one": "{{.Count}} item",
    "other": "{{.Count}} items"
  },
  "WelcomeBack": {
    "other": "Welcome back, {{.Name}}. You have {{.Count}} messages."
  }
}
Χρησιμοποιήστε περιγραφικά ID μηνυμάτων, όπως 'ItemCount' ή 'WelcomeBack', αντί για διαδρομές χωρισμένες με τελείες. Το go-i18n χρησιμοποιεί επίπεδα ID και όχι ένθετα κλειδιά. Διατηρήστε τα ID σε PascalCase, σύμφωνα με τις συμβάσεις της Go.
3

Φορτώστε το Bundle

Το Bundle είναι το κεντρικό μητρώο του go-i18n. Δημιουργήστε το κατά την εκκίνηση, καταχωρίστε τη μορφή αρχείων και φορτώστε όλα τα αρχεία μηνυμάτων. Το Bundle είναι ασφαλές για goroutines — δημιουργήστε το μία φορά και χρησιμοποιήστε το σε ολόκληρη την εφαρμογή.

main.go
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) // "こんにちは、世界!"
}
Αν εμφανιστεί το 'message not found', ελέγξτε τρία πράγματα: 1) Το αρχείο μηνυμάτων φορτώθηκε με LoadMessageFile ή MustLoadMessageFile. 2) Η επέκταση αρχείου αντιστοιχεί στην καταχωρισμένη συνάρτηση αποσειριοποίησης. 3) Το MessageID στο LocalizeConfig αντιστοιχεί ακριβώς στο κλειδί του αρχείου JSON, με διάκριση πεζών και κεφαλαίων.
4

Χρησιμοποιήστε το Localizer

Δημιουργήστε ένα Localizer για κάθε αίτημα με την προτιμώμενη γλώσσα του χρήστη. Το Localizer επιλέγει μηνύματα από το Bundle, αποδίδει πρότυπα με τη μηχανή text/template της Go και επιλέγει τη σωστή μορφή πληθυντικού βάσει του PluralCount.

Using the Localizer
// 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,
    },
})
HTTP handler with locale detection
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))
}
Το NewLocalizer δέχεται πολλές συμβολοσειρές γλώσσας και τις δοκιμάζει με τη σειρά. Περάστε απευθείας την κεφαλίδα Accept-Language: i18n.NewLocalizer(bundle, r.Header.Get("Accept-Language")). Το go-i18n αναλύει την κεφαλίδα και την αντιστοιχίζει αυτόματα με τις διαθέσιμες μεταφράσεις.
5

Χειριστείτε τους κανόνες πληθυντικού

Το go-i18n υλοποιεί κανόνες πληθυντικού CLDR για όλες τις γλώσσες. Τα Αγγλικά έχουν 2 μορφές (one, other). Τα Αραβικά έχουν 6 (zero, one, two, few, many, other). Τα Ιαπωνικά έχουν 1 (other). Ορίστε όλες τις απαιτούμενες μορφές στα αρχεία μηνυμάτων — το go-i18n επιλέγει τη σωστή βάσει του PluralCount.

Plural forms by language
// 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}}個のアイテム"
  }
}
Using plural rules
// 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: "عنصر واحد"
Τα PluralCount και TemplateData είναι ξεχωριστά. Το PluralCount επιλέγει τη μορφή πληθυντικού, ενώ το TemplateData παρέχει τιμές για την απόδοση του προτύπου. Αν χρειάζεστε τον αριθμό μέσα στο κείμενο του μηνύματος, περάστε τον και στα δύο: PluralCount: n και TemplateData: map[string]interface{'}'{"Count": n}.
6

Εντοπίστε τη γλώσσα

Στις εφαρμογές Web, εντοπίστε την προτιμώμενη γλώσσα του χρήστη από πολλές πηγές: παραμέτρους ερωτήματος, cookies, την κεφαλίδα Accept-Language ή τμήματα διαδρομής URL. Χρησιμοποιήστε το golang.org/x/text/language.Matcher για γλωσσική διαπραγμάτευση συμβατή με το BCP 47.

Locale detection middleware
// 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
})
Το language.NewMatcher επιστρέφει την καλύτερη αντιστοίχιση από τις υποστηριζόμενες γλώσσες και όχι την αρχική προτίμηση του χρήστη. Αν ένας χρήστης ζητήσει 'pt-BR' και υποστηρίζετε μόνο το 'pt', ο matcher επιστρέφει σωστά το 'pt'. Χωρίς matcher, θα χρειαζόσασταν χειροκίνητη λογική εναλλακτικής επιλογής για κάθε περιφερειακή παραλλαγή.
7

Διορθώστε την εναλλακτική επιλογή ανά κλειδί με το go-locale-chain

Το go-i18n έχει έναν γνωστό περιορισμό: μόλις αντιστοιχιστεί μια γλώσσα, δηλαδή υπάρχουν φορτωμένες μεταφράσεις γι’ αυτήν, τα κλειδιά που λείπουν δεν αναζητούνται στην επόμενη γλώσσα της αλυσίδας. Ένας χρήστης με γλώσσα pt-BR και μερικώς μεταφρασμένο αρχείο pt-BR λαμβάνει κενές συμβολοσειρές αντί να χρησιμοποιείται εναλλακτικά το pt-PT ή το pt. Το go-locale-chain το διορθώνει με εναλλακτική επιλογή ανά κλειδί σε 75 ενσωματωμένες αλυσίδες γλωσσών.

Terminal
go get github.com/i18n-agent/go-locale-chain
go-locale-chain with go-i18n
package 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
}
Το go-locale-chain είναι ένα πακέτο Go ανοικτού κώδικα χωρίς εξωτερικές εξαρτήσεις. Συμπληρώνει το go-i18n — χρησιμοποιήστε το go-i18n για φόρτωση μηνυμάτων, πληθυντικούς και απόδοση προτύπων και το go-locale-chain για σωστή επιλογή μέσω αλυσίδων εναλλακτικών γλωσσών.
Standalone usage (no go-i18n)
// 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
Χρησιμοποιήστε το ConfigureWithOverrides() για να προσαρμόσετε συγκεκριμένες αλυσίδες, διατηρώντας τις προεπιλογές. Για παράδειγμα, απλοποιήστε το pt-BR ώστε να χρησιμοποιεί εναλλακτικά μόνο το pt ή προσθέστε μια αλυσίδα για γλώσσα που δεν περιλαμβάνεται στις προεπιλογές, όπως sv-FI -> sv.
8

Αυτοματοποιήστε τις μεταφράσεις

Αφού ολοκληρώσετε τη ρύθμιση i18n, μεταφράστε τα αρχεία γλωσσών με AI. Δημιουργήστε μεταφράσεις για όλες τις γλώσσες-στόχους από το αρχικό αγγλικό αρχείο — απευθείας από το IDE ή μέσα στη διοχέτευση CI/CD.

Terminal
# 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
Μεταφράζετε σταδιακά — όταν προσθέτετε νέα ID μηνυμάτων στο αρχικό αρχείο, μεταφράζετε μόνο τα νέα κλειδιά αντί να δημιουργείτε ξανά όλα τα αρχεία. Έτσι διατηρούνται οι μεταφράσεις που έχουν ελεγχθεί από άνθρωπο.

Αυτοματοποιήστε τον έλεγχο ποιότητας των μεταφράσεων

Εντοπίστε κλειδιά που λείπουν και λανθασμένα placeholders πριν φτάσουν στην παραγωγή με το i18n-validate. Δοκιμάστε το UI με ψευδομεταφράσεις χρησιμοποιώντας το i18n-pseudo πριν είναι διαθέσιμες οι πραγματικές μεταφράσεις.

Συνηθισμένες παγίδες

Ασυμφωνία PluralCount και TemplateData

Το PluralCount επιλέγει τη μορφή πληθυντικού, αλλά δεν εισάγει την τιμή στο πρότυπο. Πρέπει επίσης να περάσετε τον αριθμό στο TemplateData, ώστε να εμφανιστεί στο αποδιδόμενο μήνυμα. Χωρίς TemplateData, το '{'{.Count}'}' αποδίδεται ως '<no value>'.

Λείπει το RegisterUnmarshalFunc

Το LoadMessageFile δεν επιστρέφει μηνύματα και δεν εμφανίζει σφάλμα, αν ξεχάσετε να καλέσετε το bundle.RegisterUnmarshalFunc() για τη μορφή αρχείου. Καταχωρίζετε πάντα το json.Unmarshal, ή το toml/yaml, πριν φορτώσετε αρχεία.

Η εναλλακτική επιλογή ανά κλειδί δεν λειτουργεί

Το NewLocalizer του go-i18n δέχεται πολλές γλώσσες, αλλά μόλις μια γλώσσα αντιστοιχιστεί σε ένα κλειδί, τα κλειδιά που λείπουν επιστρέφουν κενές συμβολοσειρές αντί να χρησιμοποιηθεί εφεδρική γλώσσα. Χρησιμοποιήστε το go-locale-chain για να το διορθώσετε με σωστή διαδοχή ανά κλειδί.

Σύνταξη προτύπου: {'{.Var}'} και όχι {'{Var}'}

Το go-i18n χρησιμοποιεί τη σύνταξη text/template της Go. Οι μεταβλητές πρέπει να έχουν πρόθεμα τελείας: {'{.Name}'} και όχι {'{Name}'}. Η τελεία αναφέρεται στον χάρτη TemplateData. Αν λείπει, προκαλείται σφάλμα εκτέλεσης προτύπου.

Προτεινόμενη δομή αρχείων

Project Structure
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.

Terminal
go get github.com/i18n-agent/go-locale-chain
Configuration
import 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 →

Συχνές ερωτήσεις για το Go i18n