Skip to main content

Pilnīgs Go internacionalizācijas ceļvedis

No ziņojumu failiem līdz gorutīnu drošai lokalizācijas atrisināšanai: iestatiet i18n Go lietotnē ar go-i18n, pēc tam automatizējiet tulkošanu ar MI.

1

Instalēt go-i18n

go-i18n ir populārākā Go internacionalizācijas bibliotēka. Tā izmanto CLDR daudzskaitļa kārtulas, Go veidnes mainīgo interpolācijai un atbalsta JSON, TOML un YAML ziņojumu failus. Valodas tagu saskaņošanai vajadzīgs arī golang.org/x/text.

go-i18n v2 vajadzīgs Go 1.16+. Pakotne golang.org/x/text nodrošina BCP 47 valodas tagu parsēšanu un saskaņošanu, ko go-i18n iekšēji izmanto daudzskaitļa kārtulu izvēlei.
Terminal
go get -u github.com/nicksnyder/go-i18n/v2/i18n
go get -u golang.org/x/text/language
2

Izveidot ziņojumu failus

Izveidojiet vienu JSON failu katrai valodai direktorijā locales. Katram ziņojumam ir ID un viena vai vairākas daudzskaitļa formas. Mainīgo interpolācijai go-i18n izmanto Go veidņu sintaksi (dubultas figūriekavas ar punkta prefiksu).

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."
  }
}
Izmantojiet aprakstošus ziņojumu ID, piemēram, „ItemCount“ vai „WelcomeBack“, nevis ar punktiem atdalītus ceļus. go-i18n izmanto plakanus ID, nevis ligzdotas atslēgas. Rakstiet ID PascalCase, lai atbilstu Go nosacījumiem.
3

Ielādēt komplektu

Bundle ir go-i18n centrālais reģistrs. Palaišanas laikā izveidojiet vienu komplektu, reģistrējiet failu formātu un ielādējiet visus ziņojumu failus. Bundle ir gorutīnu drošs — izveidojiet to vienreiz un kopīgojiet visā lietotnē.

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) // "こんにちは、世界!"
}
Ja redzat „message not found“, pārbaudiet trīs lietas: 1) ziņojumu fails ir ielādēts ar LoadMessageFile vai MustLoadMessageFile; 2) faila paplašinājums atbilst reģistrētajai atmaršalēšanas funkcijai; 3) LocalizeConfig MessageID precīzi atbilst JSON faila atslēgai (reģistrjutīgi).
4

Izmantot Localizer

Katram pieprasījumam izveidojiet Localizer ar lietotāja vēlamo valodu. Localizer atrisina ziņojumus no Bundle, apstrādā veidņu atveidi ar Go text/template dzinēju un pēc PluralCount izvēlas pareizo daudzskaitļa formu.

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 pieņem vairākas valodas virknes un izmēģina tās secīgi. Nododiet galveni Accept-Language tieši: i18n.NewLocalizer(bundle, r.Header.Get("Accept-Language")). go-i18n automātiski parsē galveni un saskaņo to ar pieejamajiem tulkojumiem.
5

Apstrādāt daudzskaitļa kārtulas

go-i18n ievieš CLDR daudzskaitļa kārtulas visām valodām. Angļu valodā ir 2 formas (one, other), arābu — 6 (zero, one, two, few, many, other), japāņu — 1 (other). Ziņojumu failos definējiet visas vajadzīgās formas, un go-i18n izvēlēsies pareizo pēc 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 un TemplateData ir atsevišķi. PluralCount izvēlas daudzskaitļa formu, bet TemplateData nodrošina vērtības veidnes atveidei. Ja skaits vajadzīgs ziņojuma tekstā, nododiet to abiem: PluralCount: n un TemplateData: map[string]interface{'}'{"Count": n}.
6

Lokalizācijas noteikšana

Tīmekļa lietotnēs nosakiet lietotāja vēlamo valodu no vairākiem avotiem: vaicājuma parametriem, sīkfailiem, galvenes Accept-Language vai URL ceļa segmentiem. BCP 47 atbilstošai valodas saskaņošanai izmantojiet golang.org/x/text/language.Matcher.

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 atgriež labāko atbilstību no atbalstītajām valodām, nevis neapstrādāto lietotāja preferenci. Ja lietotājs pieprasa 'pt-BR', bet atbalstāt tikai 'pt', saskaņotājs pareizi atgriež 'pt'. Bez saskaņotāja katram reģionālajam variantam būtu vajadzīga manuāla atkāpšanās loģika.
7

Izlabot katras atslēgas atkāpšanos ar go-locale-chain

go-i18n ir zināms ierobežojums: tiklīdz lokalizācija atbilst (ir ielādēti kaut daži tās tulkojumi), trūkstošās atslēgas nepāriet uz nākamo lokalizāciju ķēdē. pt-BR lietotājs ar daļēji tulkotu pt-BR failu saņem tukšas virknes, nevis atkāpjas uz pt-PT vai pt. go-locale-chain to novērš ar katras atslēgas atkāpšanās atrisināšanu 75 iebūvētās lokalizāciju ķēdēs.

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 ir atvērtā pirmkoda Go pakotne bez ārējām atkarībām. Tā papildina go-i18n: izmantojiet go-i18n ziņojumu ielādei, daudzskaitlim un veidņu atveidei, bet go-locale-chain — pareizai atkāpšanās ķēžu atrisināšanai.
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
Izmantojiet ConfigureWithOverrides(), lai pielāgotu konkrētas ķēdes, saglabājot noklusējumus. Piemēram, vienkāršojiet pt-BR, lai tas atkāptos tikai uz pt, vai pievienojiet ķēdi lokalizācijai, kuras nav noklusējumos, piemēram, sv-FI -> sv.
8

Automatizēt tulkošanu

Kad i18n iestatīšana ir pabeigta, tulkojiet lokalizācijas failus ar MI. Ģenerējiet visu mērķa valodu tulkojumus no angļu avota faila tieši IDE vai CI/CD konveijerā.

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
Tulkojiet pakāpeniski — pievienojot avota failam jaunus ziņojumu ID, tulkojiet tikai jaunās atslēgas, nevis ģenerējiet visus failus no jauna. Tas saglabā cilvēku pārskatītos tulkojumus.

Automatizēt tulkojumu kvalitāti

Ar i18n-validate pirms izlaišanas atrodiet trūkstošās atslēgas un bojātos vietturus. Kamēr īstie tulkojumi vēl nav gatavi, pārbaudiet UI ar i18n-pseudo pseidotulkojumiem.

Biežākās kļūdas

PluralCount un TemplateData neatbilstība

PluralCount izvēlas daudzskaitļa formu, bet neievieto vērtību veidnē. Lai tā parādītos atveidotajā ziņojumā, skaits jānodod arī TemplateData. Bez TemplateData '{'{.Count}'}' tiek atveidots kā '<no value>'.

Trūkst RegisterUnmarshalFunc

Ja faila formātam aizmirstat izsaukt bundle.RegisterUnmarshalFunc(), LoadMessageFile klusām neatgriež nevienu ziņojumu. Pirms failu ielādes vienmēr reģistrējiet json.Unmarshal (vai toml/yaml).

Katras atslēgas atkāpšanās nedarbojas

go-i18n NewLocalizer pieņem vairākas valodas, taču, tiklīdz lokalizācija atbilst vienai atslēgai, trūkstošās atslēgas atgriež tukšas virknes, nevis atkāpjas. Izlabojiet to ar go-locale-chain, kas nodrošina pareizu katras atslēgas kaskādi.

Veidnes sintakse: {'{.Var}'}, nevis {'{Var}'}

go-i18n izmanto Go text/template sintaksi. Mainīgajiem jābūt ar punkta prefiksu: {'{.Name}'}, nevis {'{Name}'}. Punkts norāda uz TemplateData karti. Bez punkta rodas veidnes izpildes kļūda.

Ieteicamā failu struktūra

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

Izmēģiniet i18n Agent tūlīt

Nometiet tulkošanas failu šeit

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

vai noklikšķiniet, lai izvēlētos

Mērķa valodas

Reģistrācija nav vajadzīgaTūlītēja tāme

Lokalizācijas atkāpšanās ar go-locale-chain

Ja reģionālajā lokalizācijā, piemēram, pt-BR, trūkst tulkojuma atslēgas, go-i18n uzreiz pāriet uz noklusējuma valodu, nevis vispirms pārbauda vecāklokalizāciju 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"},
    },
})

Pilnu atbalstīto sistēmu sarakstu un 75 iebūvētās ķēdes skatiet mūsu lokalizāciju atkāpšanās ceļvedī. Learn more →

Bieži uzdotie jautājumi par Go i18n