Skip to main content

De complete handleiding voor internationalisatie in Go

Van berichtbestanden tot goroutineveilige taalkeuze: configureer i18n in je Go-app met go-i18n en automatiseer daarna vertalingen met AI.

1

go-i18n installeren

go-i18n is de populairste bibliotheek voor internationalisatie in Go. De bibliotheek gebruikt CLDR-meervoudsregels en Go-sjablonen voor variabele interpolatie en ondersteunt berichtbestanden in JSON, TOML en YAML. Voor het vergelijken van taaltags heb je ook golang.org/x/text nodig.

go-i18n v2 vereist Go 1.16 of nieuwer. Het pakket golang.org/x/text parseert en vergelijkt BCP 47-taaltags. go-i18n gebruikt dit intern om de juiste meervoudsregels te selecteren.
Terminal
go get -u github.com/nicksnyder/go-i18n/v2/i18n
go get -u golang.org/x/text/language
2

Berichtbestanden maken

Maak voor elke taal één JSON-bestand in een map locales. Elk bericht heeft een ID en een of meer meervoudsvormen. go-i18n gebruikt Go-sjabloonsyntaxis (dubbele accolades met een punt als voorvoegsel) voor variabele interpolatie.

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."
  }
}
Gebruik beschrijvende bericht-ID's zoals 'ItemCount' of 'WelcomeBack' in plaats van paden met punten. go-i18n gebruikt platte ID's en geen geneste sleutels. Gebruik PascalCase voor ID's, in overeenstemming met de conventies van Go.
3

De Bundle laden

De Bundle is het centrale register van go-i18n. Maak er bij het opstarten één, registreer je bestandsindeling en laad alle berichtbestanden. De Bundle is goroutineveilig — maak deze eenmaal en deel hem in je hele applicatie.

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) // "こんにちは、世界!"
}
Als je 'message not found' ziet, controleer dan drie zaken: 1) het berichtbestand is geladen met LoadMessageFile of MustLoadMessageFile; 2) de bestandsextensie komt overeen met de geregistreerde unmarshal-functie; 3) de MessageID in LocalizeConfig komt exact overeen met de sleutel in je JSON-bestand (hoofdlettergevoelig).
4

De Localizer gebruiken

Maak voor elke aanvraag een Localizer met de voorkeurstaal van de gebruiker. De Localizer haalt berichten uit de Bundle, geeft sjablonen weer met de text/template-engine van Go en selecteert op basis van PluralCount de juiste meervoudsvorm.

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 accepteert meerdere taaltekenreeksen en probeert ze op volgorde. Geef de Accept-Language-header rechtstreeks door: i18n.NewLocalizer(bundle, r.Header.Get("Accept-Language")). go-i18n parseert de header en vergelijkt deze automatisch met de beschikbare vertalingen.
5

Meervoudsregels verwerken

go-i18n implementeert CLDR-meervoudsregels voor alle talen. Engels heeft 2 vormen (one, other), Arabisch 6 (zero, one, two, few, many, other) en Japans 1 (other). Definieer alle vereiste vormen in je berichtbestanden. go-i18n selecteert op basis van PluralCount de juiste vorm.

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 en TemplateData staan los van elkaar. PluralCount selecteert de meervoudsvorm en TemplateData levert waarden voor de weergave van de sjabloon. Als je het aantal in de berichttekst nodig hebt, geef je het aan beide door: PluralCount: n en TemplateData: map[string]interface{'}'{"Count": n}.
6

Talen herkennen

Herken in webapplicaties de voorkeurstaal van de gebruiker uit meerdere bronnen: queryparameters, cookies, de Accept-Language-header of URL-padsegmenten. Gebruik golang.org/x/text/language.Matcher voor taalonderhandeling die aan BCP 47 voldoet.

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 geeft de beste overeenkomst uit je ondersteunde talen terug, niet de onbewerkte gebruikersvoorkeur. Als een gebruiker 'pt-BR' aanvraagt en je alleen 'pt' ondersteunt, geeft de matcher correct 'pt' terug. Zonder matcher heb je voor elke regionale variant handmatige terugvallogica nodig.
7

Terugval per sleutel herstellen met go-locale-chain

go-i18n heeft een bekende beperking: zodra een taal overeenkomt (en vertalingen zijn geladen), vallen ontbrekende sleutels niet door naar de volgende taal in de keten. Een gebruiker met pt-BR en een gedeeltelijk vertaald pt-BR-bestand krijgt lege tekenreeksen in plaats van een terugval op pt-PT of pt. go-locale-chain lost dit op met terugval per sleutel via 75 ingebouwde taalketens.

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 is een opensource-Go-pakket zonder externe afhankelijkheden. Het vormt een aanvulling op go-i18n: gebruik go-i18n voor het laden van berichten, meervoudsvormen en sjabloonweergave en go-locale-chain voor correcte resolutie van terugvalketens.
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
Gebruik ConfigureWithOverrides() om specifieke ketens aan te passen en de standaardwaarden te behouden. Vereenvoudig pt-BR bijvoorbeeld zodat het alleen op pt terugvalt of voeg een keten toe voor een taal die niet in de standaardwaarden staat, zoals sv-FI -> sv.
8

Vertalingen automatiseren

Nu je i18n is geconfigureerd, kun je je taalbestanden met AI vertalen. Genereer vanuit je Engelstalige bronbestand vertalingen voor alle doeltalen, rechtstreeks vanuit je IDE of in je CI/CD-pipeline.

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
Vertaal stapsgewijs: vertaal alleen de nieuwe sleutels wanneer je nieuwe bericht-ID's aan je bronbestand toevoegt, in plaats van alle bestanden opnieuw te genereren. Zo blijven door mensen beoordeelde vertalingen behouden.

Kwaliteitscontrole van vertalingen automatiseren

Vind ontbrekende sleutels en kapotte plaatsaanduidingen vóór de release met i18n-validate. Test je gebruikersinterface met pseudovertalingen uit i18n-pseudo voordat de echte vertalingen klaar zijn.

Veelvoorkomende valkuilen

PluralCount en TemplateData komen niet overeen

PluralCount selecteert de meervoudsvorm, maar voegt de waarde niet in de sjabloon in. Je moet het aantal ook in TemplateData doorgeven om het in het weergegeven bericht te laten verschijnen. Zonder TemplateData wordt '{'{.Count}'}' weergegeven als '<no value>'.

RegisterUnmarshalFunc ontbreekt

LoadMessageFile geeft zonder melding geen berichten terug als je vergeet bundle.RegisterUnmarshalFunc() voor de bestandsindeling aan te roepen. Registreer altijd json.Unmarshal (of toml/yaml) voordat je bestanden laadt.

Terugval per sleutel werkt niet

NewLocalizer van go-i18n accepteert meerdere talen, maar zodra een taal voor één sleutel overeenkomt, geven ontbrekende sleutels lege tekenreeksen terug in plaats van terug te vallen. Gebruik go-locale-chain om dit met een correcte cascade per sleutel te herstellen.

Sjabloonsyntaxis: {'{.Var}'} en niet {'{Var}'}

go-i18n gebruikt de text/template-syntaxis van Go. Variabelen moeten een punt als voorvoegsel hebben: {'{.Name}'} en niet {'{Name}'}. De punt verwijst naar de TemplateData-map. Zonder de punt treedt een fout op bij het uitvoeren van de sjabloon.

Aanbevolen bestandsstructuur

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

Probeer i18n Agent nu

Zet je vertaalbestand hier neer

JSON, YAML, PO, XML, CSV, Markdown, Properties

of klik om een bestand te selecteren

Doeltalen

Geen registratie nodigDirecte prijsindicatie

Locale-fallback met go-locale-chain

Wanneer een vertaalsleutel ontbreekt in een regionale taalvariant zoals pt-BR, springt go-i18n rechtstreeks naar de standaardtaal in plaats van eerst de bovenliggende taal pt te controleren.

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"},
    },
})

Bekijk onze handleiding voor locale-fallbacks voor de volledige lijst met ondersteunde frameworks en 75 ingebouwde ketens. Learn more →

Veelgestelde vragen over Go-i18n