Skip to main content

Der vollständige Leitfaden zur Go-Internationalisierung

Von Nachrichtendateien bis zur Goroutine-sicheren Locale-Auflösung: Richten Sie i18n mit go-i18n in Ihrer Go-App ein und automatisieren Sie anschließend Übersetzungen mit KI.

1

go-i18n installieren

go-i18n ist die beliebteste Internationalisierungsbibliothek für Go. Sie verwendet CLDR-Pluralregeln, Go-Vorlagen zur Variableninterpolation und unterstützt JSON-, TOML- und YAML-Nachrichtendateien. Außerdem benötigen Sie golang.org/x/text zum Abgleichen von Sprach-Tags.

go-i18n v2 erfordert Go 1.16+. Das Paket golang.org/x/text stellt das BCP-47-konforme Parsen und Abgleichen von Sprach-Tags bereit, das go-i18n intern zur Auswahl von Pluralregeln verwendet.
Terminal
go get -u github.com/nicksnyder/go-i18n/v2/i18n
go get -u golang.org/x/text/language
2

Nachrichtendateien erstellen

Erstellen Sie in einem locales-Verzeichnis eine JSON-Datei pro Sprache. Jede Nachricht besitzt eine ID und eine oder mehrere Pluralformen. go-i18n verwendet zur Variableninterpolation die Go-Vorlagensyntax mit doppelten geschweiften Klammern und Punktpräfix.

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."
  }
}
Verwenden Sie beschreibende Nachrichten-IDs wie ItemCount oder WelcomeBack statt durch Punkte getrennter Pfade. go-i18n verwendet flache IDs, keine verschachtelten Schlüssel. Schreiben Sie IDs gemäß den Go-Konventionen in PascalCase.
3

Bundle laden

Das Bundle ist das zentrale Register von go-i18n. Erstellen Sie es einmal beim Start, registrieren Sie Ihr Dateiformat und laden Sie sämtliche Nachrichtendateien. Das Bundle ist Goroutine-sicher – erstellen Sie es einmal und teilen Sie es in Ihrer Anwendung.

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) // "こんにちは、世界!"
}
Wenn „message not found“ erscheint, prüfen Sie drei Punkte: 1) Die Nachrichtendatei wurde mit LoadMessageFile oder MustLoadMessageFile geladen. 2) Die Dateierweiterung entspricht der registrierten Unmarshal-Funktion. 3) Die MessageID in LocalizeConfig stimmt exakt mit dem Schlüssel Ihrer JSON-Datei überein (Groß-/Kleinschreibung beachten).
4

Localizer verwenden

Erstellen Sie für jede Anfrage einen Localizer mit der bevorzugten Sprache. Der Localizer löst Nachrichten aus dem Bundle auf, verarbeitet Vorlagen mit der Go-Engine text/template und wählt anhand von PluralCount die richtige Pluralform.

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 akzeptiert mehrere Sprachzeichenfolgen und versucht sie der Reihe nach. Übergeben Sie den Accept-Language-Header direkt: i18n.NewLocalizer(bundle, r.Header.Get("Accept-Language")). go-i18n parst den Header und gleicht ihn automatisch mit verfügbaren Übersetzungen ab.
5

Pluralregeln verarbeiten

go-i18n implementiert CLDR-Pluralregeln für alle Sprachen. Englisch hat zwei Formen (one, other), Arabisch sechs (zero, one, two, few, many, other), Japanisch eine (other). Definieren Sie alle erforderlichen Formen in Ihren Nachrichtendateien; go-i18n wählt anhand von PluralCount die richtige aus.

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 und TemplateData sind getrennt. PluralCount wählt die Pluralform, TemplateData liefert Werte für das Vorlagenrendering. Wenn die Anzahl im Nachrichtentext erscheinen soll, übergeben Sie sie in beiden: PluralCount: n und TemplateData: map[string]interface{'}'{"Count": n}.
6

Locale-Erkennung

Erkennen Sie in Webanwendungen die bevorzugte Sprache aus mehreren Quellen: Abfrageparameter, Cookies, Accept-Language-Header oder URL-Pfadsegmente. Verwenden Sie golang.org/x/text/language.Matcher für BCP-47-konforme Sprachaushandlung.

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 gibt die beste Übereinstimmung aus Ihren unterstützten Sprachen zurück, nicht die unverarbeitete Präferenz. Fordert eine Person pt-BR an und unterstützen Sie nur pt, gibt der Matcher korrekt pt zurück. Ohne Matcher müssten Sie für jede regionale Variante eigene Fallback-Logik schreiben.
7

Schlüsselbezogenen Fallback mit go-locale-chain beheben

go-i18n weist eine bekannte Einschränkung auf: Sobald eine Locale übereinstimmt und Übersetzungen geladen sind, fallen fehlende Schlüssel nicht auf die nächste Locale der Kette zurück. Eine Person mit pt-BR und teilweise übersetzter pt-BR-Datei erhält leere Zeichenfolgen statt eines Fallbacks auf pt-PT oder pt. go-locale-chain behebt dies mit schlüsselbezogener Auflösung über 75 integrierte Locale-Ketten.

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 ist ein quelloffenes Go-Paket ohne externe Abhängigkeiten. Es ergänzt go-i18n: Verwenden Sie go-i18n zum Laden von Nachrichten, für Pluralbildung und Vorlagenrendering und go-locale-chain für die korrekte Auflösung von Fallback-Ketten.
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
Passen Sie einzelne Ketten mit ConfigureWithOverrides() an und behalten Sie die Standardwerte bei. Vereinfachen Sie beispielsweise pt-BR auf einen alleinigen Fallback zu pt oder ergänzen Sie eine Kette für eine nicht enthaltene Locale wie sv-FI -> sv.
8

Übersetzungen automatisieren

Wenn Ihre i18n-Einrichtung abgeschlossen ist, übersetzen Sie Ihre Locale-Dateien mit KI. Erzeugen Sie Übersetzungen für alle Zielsprachen aus Ihrer englischen Ausgangsdatei – direkt aus Ihrer IDE oder in Ihrer 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
Übersetzen Sie schrittweise: Wenn Sie Ihrer Ausgangsdatei neue Nachrichten-IDs hinzufügen, übersetzen Sie nur die neuen Schlüssel, statt sämtliche Dateien neu zu erzeugen. So bleiben von Menschen geprüfte Übersetzungen erhalten.

Übersetzungsqualität automatisieren

Erkennen Sie mit i18n-validate fehlende Schlüssel und beschädigte Platzhalter vor der Veröffentlichung. Testen Sie Ihre Benutzeroberfläche mit i18n-pseudo und Pseudoübersetzungen, bevor echte Übersetzungen vorliegen.

Häufige Fallstricke

PluralCount und TemplateData stimmen nicht überein

PluralCount wählt die Pluralform, fügt den Wert aber nicht in die Vorlage ein. Sie müssen die Anzahl zusätzlich in TemplateData übergeben, damit sie in der gerenderten Nachricht erscheint. Ohne TemplateData rendert '{'{.Count}'}' als '<no value>'.

RegisterUnmarshalFunc fehlt

LoadMessageFile gibt unbemerkt keine Nachrichten zurück, wenn Sie bundle.RegisterUnmarshalFunc() für das Dateiformat nicht aufrufen. Registrieren Sie vor dem Laden der Dateien stets json.Unmarshal oder die entsprechende TOML-/YAML-Funktion.

Schlüsselbezogener Fallback funktioniert nicht

NewLocalizer von go-i18n akzeptiert mehrere Sprachen. Sobald eine Locale jedoch mit einem einzigen Schlüssel übereinstimmt, ergeben fehlende Schlüssel leere Zeichenfolgen statt eines Fallbacks. Beheben Sie dies mit einer korrekten schlüsselbezogenen Kaskade über go-locale-chain.

Vorlagensyntax: {'{.Var}'} statt {'{Var}'}

go-i18n verwendet die Go-Syntax text/template. Variablen benötigen ein Punktpräfix: {'{.Name}'}, nicht {'{Name}'}. Der Punkt verweist auf die TemplateData-Map. Fehlt er, tritt ein Fehler bei der Vorlagenausführung auf.

Empfohlene Dateistruktur

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 jetzt testen

Legen Sie Ihre Übersetzungsdatei hier ab

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

oder zum Auswählen klicken

Zielsprachen

Keine Registrierung erforderlichSofortiges Angebot

Locale-Fallback mit go-locale-chain

Fehlt ein Übersetzungsschlüssel in einer regionalen Locale wie pt-BR, wechselt go-i18n direkt zur Standardsprache, statt zuerst die übergeordnete Locale pt zu prüfen.

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

In unserem Leitfaden zu Locale-Fallbacks finden Sie die vollständige Liste unterstützter Frameworks und 75 integrierter Ketten. Learn more →

Häufig gestellte Fragen zu Go-i18n