Skip to main content

Den komplette guide til internationalisering med Go

Fra meddelelsesfiler til goroutinesikker fastlæggelse af landestandard: Konfigurer i18n i din Go-app med go-i18n og automatiser derefter oversættelser med AI.

1

Installer go-i18n

go-i18n er det mest populære internationaliseringsbibliotek til Go. Det bruger CLDR-flertalsregler og Go-skabeloner til variabelinterpolation og understøtter meddelelsesfiler i JSON-, TOML- og YAML-format. Du skal også bruge golang.org/x/text til at matche sprogtags.

go-i18n v2 kræver Go 1.16+. Pakken golang.org/x/text understøtter fortolkning og matchning af BCP 47-sprogtags, som go-i18n bruger internt til at vælge flertalsregler.
Terminal
go get -u github.com/nicksnyder/go-i18n/v2/i18n
go get -u golang.org/x/text/language
2

Opret meddelelsesfiler

Opret én JSON-fil pr. sprog i en locales-mappe. Hver meddelelse har et ID og en eller flere flertalsformer. Go-i18n bruger Go-skabelonsyntaks (dobbelte krøllede parenteser med et punktum som præfiks) til variabelinterpolation.

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."
  }
}
Brug beskrivende meddelelses-ID'er som 'ItemCount' eller 'WelcomeBack' frem for punktumseparerede stier. go-i18n bruger flade ID'er, ikke indlejrede nøgler. Behold ID'er i PascalCase, så de følger Go-konventionerne.
3

Indlæs Bundle

Bundle er go-i18n's centrale register. Opret én ved opstart, registrer dit filformat og indlæs alle meddelelsesfiler. Bundle er goroutinesikker — opret den én gang og del den på tværs af din applikation.

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) // "こんにちは、世界!"
}
Hvis du ser 'message not found', skal du kontrollere tre ting: 1) Meddelelsesfilen blev indlæst med LoadMessageFile eller MustLoadMessageFile. 2) Filendelsen svarer til den registrerede funktion til deserialisering. 3) MessageID i LocalizeConfig svarer nøjagtigt til nøglen i din JSON-fil (der skelnes mellem store og små bogstaver).
4

Brug Localizer

Opret en Localizer til hver anmodning med brugerens foretrukne sprog. Localizer finder meddelelser i Bundle, håndterer skabelongengivelse med Gos text/template-motor og vælger den korrekte flertalsform ud fra 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 accepterer flere sprogstrenge — den afprøver dem i rækkefølge. Overfør Accept-Language-headeren direkte: i18n.NewLocalizer(bundle, r.Header.Get("Accept-Language")). go-i18n fortolker automatisk headeren og matcher den med de tilgængelige oversættelser.
5

Håndter flertalsregler

go-i18n implementerer CLDR-flertalsregler for alle sprog. Engelsk har 2 former (one, other). Arabisk har 6 (zero, one, two, few, many, other). Japansk har 1 (other). Definer alle nødvendige former i dine meddelelsesfiler — go-i18n vælger den korrekte ud fra 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 og TemplateData er separate. PluralCount vælger flertalsformen, mens TemplateData leverer værdier til skabelongengivelsen. Hvis antallet skal indgå i meddelelsesteksten, skal du overføre det begge steder: PluralCount: n and TemplateData: map[string]interface{'}'{"Count": n}.
6

Registrering af landestandard

I webapplikationer kan du registrere brugerens foretrukne sprog fra flere kilder: forespørgselsparametre, cookies, Accept-Language-headeren eller URL-stisegmenter. Brug golang.org/x/text/language.Matcher til sprogforhandling i overensstemmelse med 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 returnerer det bedste match blandt dine understøttede sprog, ikke den rå brugerpræference. Hvis en bruger anmoder om 'pt-BR' og du kun understøtter 'pt', returnerer matcheren korrekt 'pt'. Uden en matcher skulle du bruge manuel fallbacklogik til hver regional variant.
7

Ret fallback pr. nøgle med go-locale-chain

go-i18n har en kendt begrænsning: Når en landestandard først matcher (og har indlæst nogen oversættelser), går manglende nøgler ikke videre til den næste landestandard i kæden. En pt-BR-bruger med en delvist oversat pt-BR-fil får tomme strenge i stedet for fallback til pt-PT eller pt. go-locale-chain løser dette med fallback pr. nøgle på tværs af 75 indbyggede landestandardkæder.

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 er en Go-pakke med åben kildekode og uden eksterne afhængigheder. Den supplerer go-i18n — brug go-i18n til indlæsning af meddelelser, flertalsbøjning og skabelongengivelse og go-locale-chain til korrekt behandling af fallbackkæder.
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
Brug ConfigureWithOverrides() til at tilpasse bestemte kæder og samtidig bevare standarderne. Du kan f.eks. forenkle pt-BR, så den kun falder tilbage til pt eller tilføje en kæde til en landestandard, der ikke findes i standarderne, som sv-FI -> sv.
8

Automatiser oversættelser

Når din i18n-opsætning er færdig, kan du oversætte dine landestandardfiler med AI. Generer oversættelser til alle målsprog ud fra din engelske kildefil — direkte fra din IDE eller i din 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
Oversæt trinvist — når du tilføjer nye meddelelses-ID'er til kildefilen, skal du kun oversætte de nye nøgler frem for at generere alle filer igen. Det bevarer eventuelle oversættelser, som er blevet gennemgået af mennesker.

Automatiser oversættelseskvaliteten

Find manglende nøgler og ugyldige pladsholdere med i18n-validate, før de udgives. Test din brugergrænseflade med pseudooversættelser ved hjælp af i18n-pseudo, før de rigtige oversættelser er klar.

Almindelige faldgruber

Uoverensstemmelse mellem PluralCount og TemplateData

PluralCount vælger flertalsformen, men indsætter ikke værdien i skabelonen. Du skal også overføre antallet i TemplateData, for at det vises i den gengivne meddelelse. Uden TemplateData gengives '{'{.Count}'}' som '<no value>'.

Manglende RegisterUnmarshalFunc

LoadMessageFile returnerer i stilhed ingen meddelelser, hvis du glemmer at kalde bundle.RegisterUnmarshalFunc() for filformatet. Registrer altid json.Unmarshal (eller toml/yaml), før du indlæser filer.

Fallback pr. nøgle fungerer ikke

go-i18n's NewLocalizer accepterer flere sprog, men når en landestandard først matcher en enkelt nøgle, returnerer manglende nøgler tomme strenge i stedet for at falde tilbage. Brug go-locale-chain til at løse dette med en korrekt fallbackkæde pr. nøgle.

Skabelonsyntaks: {'{.Var}'}, ikke {'{Var}'}

go-i18n bruger Go's text/template-syntaks. Variabler skal have et punktum som præfiks: {'{.Name}'}, ikke {'{Name}'}. Punktummet henviser til TemplateData-mappet. Hvis punktummet mangler, opstår der en fejl under kørsel af skabelonen.

Anbefalet filstruktur

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

Prøv i18n Agent nu

Slip din oversættelsesfil her

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

eller klik for at vælge en fil

Målsprog

Kræver ingen tilmeldingEstimat med det samme

Fallback af landestandard med go-locale-chain

Når en oversættelsesnøgle mangler i en regional landestandard som pt-BR, springer go-i18n direkte til standardsproget i stedet for først at kontrollere den overordnede landestandard 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"},
    },
})

Se vores guide til fallback af landestandarder for at få den komplette liste over understøttede frameworks og 75 indbyggede kæder. Learn more →

Ofte stillede spørgsmål om Go i18n