Skip to main content

Den kompletta guiden till internationalisering i Go

Från meddelandefiler till goroutine-säker språkvariantshantering: konfigurera i18n i din Go-app med go-i18n och automatisera sedan översättningar med AI.

1

Installera go-i18n

go-i18n är det populäraste internationaliseringsbiblioteket för Go. Det använder CLDR-pluralregler och Go-mallar för variabelinterpolering samt stöder meddelandefiler i JSON, TOML och YAML. Du behöver även golang.org/x/text för matchning av språktaggar.

go-i18n v2 kräver Go 1.16+. Paketet golang.org/x/text tillhandahåller tolkning och matchning av BCP 47-språktaggar, vilket go-i18n använder internt för att välja pluralregel.
Terminal
go get -u github.com/nicksnyder/go-i18n/v2/i18n
go get -u golang.org/x/text/language
2

Skapa meddelandefiler

Skapa en JSON-fil per språk i katalogen locales. Varje meddelande har ett ID och en eller flera pluralformer. Go-i18n använder Go-mallsyntax (dubbla klammerparenteser med punktprefix) för variabelinterpolering.

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."
  }
}
Använd beskrivande meddelande-ID:n som 'ItemCount' eller 'WelcomeBack' i stället för punktavgränsade sökvägar. go-i18n använder platta ID:n, inte nästlade nycklar. Använd PascalCase för ID:n i enlighet med Go-konventionerna.
3

Läs in Bundle

Bundle är go-i18n:s centrala register. Skapa ett vid start, registrera filformatet och läs in alla meddelandefiler. Bundle är goroutine-säkert – skapa det en gång och dela det i hela applikationen.

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) // "こんにちは、世界!"
}
Om du ser 'message not found' ska du kontrollera tre saker: 1) Att meddelandefilen lästes in med LoadMessageFile eller MustLoadMessageFile. 2) Att filändelsen matchar den registrerade avserialiseringsfunktionen. 3) Att MessageID i LocalizeConfig exakt matchar nyckeln i JSON-filen (skiftlägeskänsligt).
4

Använd Localizer

Skapa en Localizer för varje begäran med användarens föredragna språk. Localizer hämtar meddelanden från Bundle, hanterar mallrendering med Go:s text/template-motor och väljer rätt pluralform utifrån 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 tar emot flera språksträngar och provar dem i tur och ordning. Skicka Accept-Language-rubriken direkt: i18n.NewLocalizer(bundle, r.Header.Get("Accept-Language")). go-i18n tolkar rubriken och matchar den automatiskt mot tillgängliga översättningar.
5

Hantera pluralregler

go-i18n implementerar CLDR-pluralregler för alla språk. Engelska har 2 former (one, other). Arabiska har 6 (zero, one, two, few, many, other). Japanska har 1 (other). Definiera alla obligatoriska former i meddelandefilerna – go-i18n väljer rätt form utifrån 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 och TemplateData är separata. PluralCount väljer pluralformen medan TemplateData tillhandahåller värden för mallrenderingen. Om antalet ska visas i meddelandet måste du skicka det i båda: PluralCount: n och TemplateData: map[string]interface{'}'{"Count": n}.
6

Identifiera språkvariant

Identifiera användarens föredragna språk från flera källor i webbapplikationer: frågeparametrar, cookies, Accept-Language-rubriken eller URL-sökvägssegment. Använd golang.org/x/text/language.Matcher för språkförhandling enligt 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 returnerar den bästa matchningen bland språken som stöds, inte användarens obearbetade önskemål. Om en användare begär 'pt-BR' och du bara stöder 'pt' returnerar matcharen korrekt 'pt'. Utan en matchare skulle du behöva manuell reservlogik för varje regional variant.
7

Åtgärda reservhantering per nyckel med go-locale-chain

go-i18n har en känd begränsning: när en språkvariant väl matchar (och har några inlästa översättningar) går saknade nycklar inte vidare till nästa språkvariant i kedjan. En användare med pt-BR och en delvis översatt pt-BR-fil får tomma strängar i stället för reservöversättningar från pt-PT eller pt. go-locale-chain åtgärdar detta med reservhantering per nyckel i 75 inbyggda språkvariantkedjor.

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 är ett Go-paket med öppen källkod och utan externa beroenden. Det kompletterar go-i18n – använd go-i18n för meddelandeinläsning, pluralhantering och mallrendering och go-locale-chain för korrekt hantering av reservkedjor.
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
Använd ConfigureWithOverrides() för att anpassa enskilda kedjor och samtidigt behålla standardvärdena. Du kan till exempel förenkla pt-BR så att endast pt används som reserv eller lägga till en kedja för en språkvariant som inte ingår i standardvärdena, exempelvis sv-FI -> sv.
8

Automatisera översättningar

När i18n-konfigurationen är klar kan du översätta språkfilerna med AI. Generera översättningar till alla målspråk från den engelska källfilen – direkt i utvecklingsmiljön eller i ditt CI/CD-flöde.

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
Översätt stegvis – när du lägger till nya meddelande-ID:n i källfilen översätter du bara de nya nycklarna i stället för att generera om alla filer. Då bevaras översättningar som har granskats av människor.

Automatisera översättningskvaliteten

Upptäck saknade nycklar och trasiga platshållare med i18n-validate innan de når produktion. Testa gränssnittet med pseudoöversättningar via i18n-pseudo innan de riktiga översättningarna är klara.

Vanliga fallgropar

PluralCount och TemplateData stämmer inte överens

PluralCount väljer pluralformen, men matar inte in värdet i mallen. Du måste även skicka antalet i TemplateData för att det ska visas i det renderade meddelandet. Utan TemplateData renderas '{'{.Count}'}' som '<no value>'.

RegisterUnmarshalFunc saknas

LoadMessageFile returnerar inga meddelanden och ger inget felmeddelande om du glömmer att anropa bundle.RegisterUnmarshalFunc() för filformatet. Registrera alltid json.Unmarshal (eller toml/yaml) innan du läser in filer.

Reservhantering per nyckel fungerar inte

NewLocalizer i go-i18n tar emot flera språk, men när en språkvariant matchar en enda nyckel returnerar saknade nycklar tomma strängar i stället för att använda en reserv. Använd go-locale-chain för att åtgärda detta med en korrekt kaskad per nyckel.

Mallsyntax: {'{.Var}'}, inte {'{Var}'}

go-i18n använder Go:s text/template-syntax. Variabler måste ha ett punktprefix: {'{.Name}'}, inte {'{Name}'}. Punkten refererar till TemplateData-mappningen. Om punkten saknas uppstår ett fel när mallen körs.

Rekommenderad 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

Prova i18n Agent nu

Släpp din översättningsfil här

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

eller klicka för att välja en fil

Målspråk

Ingen registrering krävsPrisuppskattning direkt

Språkreserv med go-locale-chain

När en översättningsnyckel saknas i en regional språkvariant som pt-BR går go-i18n direkt till standardspråket i stället för att först kontrollera den överordnade språkvarianten 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"},
    },
})

I vår guide till språkreserver finns en fullständig lista över ramverk som stöds och 75 inbyggda kedjor. Learn more →

Vanliga frågor om Go i18n