Translate your Go program into multiple languages.

go-i18n Build status Report card codecov Sourcegraph

go-i18n is a Go package and a command that helps you translate Go programs into multiple languages.

Package i18n GoDoc

The i18n package provides support for looking up messages according to a set of locale preferences.

import "github.com/nicksnyder/go-i18n/v2/i18n"

Create a Bundle to use for the lifetime of your application.

bundle := i18n.NewBundle(language.English)

Load translations into your bundle during initialization.

bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
bundle.LoadMessageFile("es.toml")

Create a Localizer to use for a set of language preferences.

func(w http.ResponseWriter, r *http.Request) {
    lang := r.FormValue("lang")
    accept := r.Header.Get("Accept-Language")
    localizer := i18n.NewLocalizer(bundle, lang, accept)
}

Use the Localizer to lookup messages.

localizer.Localize(&i18n.LocalizeConfig{
    DefaultMessage: &i18n.Message{
        ID: "PersonCats",
        One: "{{.Name}} has {{.Count}} cat.",
        Other: "{{.Name}} has {{.Count}} cats.",
    },
    TemplateData: map[string]interface{}{
        "Name": "Nick",
        "Count": 2,
    },
    PluralCount: 2,
}) // Nick has 2 cats.

Command goi18n GoDoc

The goi18n command manages message files used by the i18n package.

go get -u github.com/nicksnyder/go-i18n/v2/goi18n
goi18n -help

Extracting messages

Use goi18n extract to extract all i18n.Message struct literals in Go source files to a message file for translation.

# active.en.toml
[PersonCats]
description = "The number of cats a person has"
one = "{{.Name}} has {{.Count}} cat."
other = "{{.Name}} has {{.Count}} cats."

Translating a new language

  1. Create an empty message file for the language that you want to add (e.g. translate.es.toml).

  2. Run goi18n merge active.en.toml translate.es.toml to populate translate.es.toml with the messages to be translated.

    # translate.es.toml
    [HelloPerson]
    hash = "sha1-5b49bfdad81fedaeefb224b0ffc2acc58b09cff5"
    other = "Hello {{.Name}}"
  3. After translate.es.toml has been translated, rename it to active.es.toml.

    # active.es.toml
    [HelloPerson]
    hash = "sha1-5b49bfdad81fedaeefb224b0ffc2acc58b09cff5"
    other = "Hola {{.Name}}"
  4. Load active.es.toml into your bundle.

    bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
    bundle.LoadMessageFile("active.es.toml")

Translating new messages

If you have added new messages to your program:

  1. Run goi18n extract to update active.en.toml with the new messages.
  2. Run goi18n merge active.*.toml to generate updated translate.*.toml files.
  3. Translate all the messages in the translate.*.toml files.
  4. Run goi18n merge active.*.toml translate.*.toml to merge the translated messages into the active message files.

For more information and examples:

License

go-i18n is available under the MIT license. See the LICENSE file for more info.

Comments
  • Release v2.0.0

    Release v2.0.0

    I have started to prototype what v2 of this library might look like.

    The overall goals of v2 are to

    1. Address all issues that are currently open on the project
    2. Apply some Go best practices to the codebase (e.g. remove global state, explicit error returns)
    3. Revisit API design and make breaking changes which are necessary to accomplish (1) and (2).

    My development plan is to work on this in a branch until I am happy with the results. Then, I will merge this into master under a subfolder called v2-beta and tag a 1.x.0 release. Projects can then begin to try out the new API and provide feedback. APIs under v2-beta subfolder will be subject to change pending community feedback. Once I am happy with the results, I will make a final 1.x.0 release that contains the v2 api under the v2 subfolder. ~~Immediately following that, I will delete the v1 package files, move v2-beta to the root of the repository, and tag 2.0.0.~~

    I do not have an estimate for when this work will be complete as I am working on it in spare time here and there.

    If you have general feedback about this process it can be shared here. If there are other things you would want to see in a world where breaking API changes are possible, please create a new issue and I will consider it.

  • How do you handle l10n ?

    How do you handle l10n ?

    How do you handle the format for dates, numbers, etc.. ?

    How about stealing this: https://github.com/jbnicolai/closure-library/blob/20702eff5afe0fd9d8c5a42254879fc18c34253b/closure/goog/i18n/datetimepatternsext.js ?

    For example, the angular folks leverage it through their https://docs.angularjs.org/api/ng/filter/date filter.. same with number and currency filters..

  • Allow use custom language codes

    Allow use custom language codes

    Fix #72 Fix https://github.com/spf13/hugo/issues/3564

    go-i18n doesn't return an error now, if user provides non-registered language code.

    /cc @bep @nicksnyder

  • bundle: runtime-reflect structs to map[string]interface{}

    bundle: runtime-reflect structs to map[string]interface{}

    Fixes #24.

    @nicksnyder The structs package is quite lightweight. It is also licensed under MIT. I can attempt to extract the Struct.structFields() and Struct.Map() methods if you would prefer.

  • Odd behaviour with DefaultMessage

    Odd behaviour with DefaultMessage

    Working on https://github.com/gohugoio/hugo/pull/5243 and trying to find a workaround for #124 I found some odd behaviour with DefaultMessage

    translated, err := localizer.Localize(&i18n.LocalizeConfig{
    				//DefaultMessage: defaultMessage,
    				MessageID:    translationID,
    				TemplateData: templateData,
    			})
    

    I have a test case which returns translated as expected and no error with the code above. If I uncomment the DefaultMessage, I always get the default message in return.

  • The command

    The command "goi18n constants" is missing

    Hello! I use "github.com/nicksnyder/go-i18n/v2/i18n" and I want to use the command "goi18n constants", but for some reason it is unavailable in the 2nd version of this package.

    I tried to use the first version of the package to generate constants, but it seems that it is incompatible with the format of the 2nd version:

    goi18n constants es.toml
    failed to load translation file es.toml because unable to parse translation #0 because invalid plural category description
    map[id:PersonCats translation:map[description:The number of cats a person has one:{{.Name}} has {{.Count}} cat. other:{{.Name}} has {{.Count}} cats.]]
    
    # es.toml
    [PersonCats]
    description = "The number of cats a person has"
    one = "{{.Name}} has {{.Count}} cat."
    other = "{{.Name}} has {{.Count}} cats."
    

    Can you explain why this command is not available in the second version of the package and do you have plans to return it?

  • [Feature] Command goi18n generate dynamic struct R.go

    [Feature] Command goi18n generate dynamic struct R.go

    Working with Android/Java the IDE generates a dynamic class R.java with all strings ids, this method avoid a lot of bugs. In a big project is easy to reference an invalid id or to have a lot of unused ids.

    What do you think the command goi18n generates R.go ? Example:

    en-US.all.json

    [
      {
        "id": "settings_title",
        "translation": "Settings"
      }
    ]
    
    $ goi18n -genconst en-US.all.json -outdir ./
    

    this command generates R.go

    package R
    const SettingsTitle string = "settings_title"
    

    In code the new way will be:

    T(R.SettingsTitle)
    

    This is only a suggestion, let me know what do you think. I can help with this change thanks

  • Question: {{T

    Question: {{T "messageID" .Param1 .Param2}} in v2

    Hi, just found this package today, played around with v2 a little bit, and it works great. Great package.

    My goal is to use translations from html/template files only, like this:

    {{T "messageID" .Param1 .Param2}}
    

    I see that there isn't a Tfunc() in v2 as opposed to v1 so I wrote a wrapper:

    lang := r.FormValue("lang")
    accept := r.Header.Get("Accept-Language")
    localizer := i18n.NewLocalizer(bundle, lang, accept)
    T := func(messageID string, args ...interface{}) string {
    	lc := i18n.LocalizeConfig{MessageID: messageID}
    	if len(args) > 1 {
    		lc.PluralCount = args[0]
    		td := make(map[string]interface{})
    		td["PluralCount"] = lc.PluralCount
    		for i := 1; i < len(args); i++ {
    			td["P"+strconv.Itoa(i)] = args[i]
    		}
    		lc.TemplateData = td
    	}
    	return localizer.MustLocalize(&lc)
    }
    t.Funcs(map[string]interface{}{
    	"T": T,
    })
    ...
    

    This makes it possbile to have a translation like this:

    [PersonUnreadEmails]
    description = "The number of unread emails a person has"
    one = "{{.P1}} has {{.PluralCount}} unread email."
    other = "{{.P1}} has {{.PluralCount}} unread emails."
    

    So the first argument is always translated to PluralCount and the rest is numbered, like P1, P2 and so on, and then I can use it like this:

    {{T "PersonUnreadEmails" .NumberOfUnreadEmail .PersonName}}
    

    This works perfectly but is this also how you would do it? Is there a better way?

  • Preferences don't cascade on translation

    Preferences don't cascade on translation

    Hey, @nicksnyder! Ran into an issue today you might find interesting. Here's my situation.

    I have three files, all for English: en.all.json, en-US.all.json, and en-GB.all.json. The first holds all English translations that are common between all variations of English we support. The second and third files hold translations specific to their respective locales.

    A user requests something from us, and sends us the locale en-US. We make a TranslationFunc with preferences en-US, en. Now here's where we run into a problem: if I ask for a translation that is not in en-US.all.json, it returns the translationID instead of looking inside en.all.json for a relevant translation.

    This is due to the way bundle.TfuncAndLanguage handles language preferences. When I ask for en-US and the language has any translations, it limits the search to this map, ignoring the remaining language preferences.

    I'd like to support the preference fallback at the translation level, instead of the language level. In pseudocode, this is:

    translation_id = "my_string"
    preferences = %[en-US en]
    
    # Upon request for a translation, iterate through each & return
    # if any of the preferences contain the translation.
    preferences.each do |pref|
      if translations[pref] && translations[pref][translation_id]
        # A translation was found.
        return translations[pref][translation_id]
      end
    end
    # If no langs have matching translations, return the translation ID.
    return translation_id
    

    What do you think?

  • example ?

    example ?

    Hello

    I am looking for a way to build translation into a web-based project. I came across this and it really looks impressive. However, I have no idea where to start; I am puzzled how the whole framework is to be integrated in a project. It would be great if there was a minimum sample project somewhere, showing how this is done ?

  • Export SupportedLanguage

    Export SupportedLanguage

    I'd like to know which language go-i18n decided to use among the candidates caller provided to Tfunc, for example save the language into database for pushing localized content afterwards.

  • Hook to commonly catch errors

    Hook to commonly catch errors

    hey. First of all, Thanks for maintaining this library which helped me localize go serviceseaily.

    I'm using this lib in couple of instances. I want to track all the missing translation (MessageNotFound) error for future reporting and fixes. I searched through the docs and cannot find a onError kinda hook something similar to react-intl's onError hook. Is there any recommendations on this? I would be happy to build one :) Thanks

  • Cound you export this function or when translation has error get the original value

    Cound you export this function or when translation has error get the original value

    code: https://github.com/nicksnyder/go-i18n/blob/639caa7eb5031c3fc275d5b3bf1f44fe3c3f2623/v2/i18n/localizer.go#L181

    repeat issue: https://github.com/nicksnyder/go-i18n/issues/275#issuecomment-1179462892

    language.yaml:

    base:
      foo: "foo {{ bar }} "
    

    when I want to translate base.foo, it will be get error tips: function "bar" not defined. I wish the key base.foo is exists, I'll get the string value foo {{ bar }} for translate result,and the err tip. if the key is not exists, I'll get the err and empty result.

  • `goi18n extract` doesn't seem to work for source file that use generics

    `goi18n extract` doesn't seem to work for source file that use generics

    When trying to use goi18n extract on my project that uses generics I'm getting the following error:

    10:17: expected '(', found '[' (and 3 more errors)
    

    I'm guessing that is due to the generics type parameters that start with a [ when a regular function would directly have a ( before listing the regular parameters.

    I'm guessing this issue comes from /v2/goi18n/extract_command.go:122 parser.ParseFile(fset, "", buf, parser.AllErrors)

    Would increasing the version of golang used in this project from go1.12 to go1.18 fix this issue? I'm guessing then the package go/parser would be able to parse generics correctly.

  • How to generate translations for the toml files

    How to generate translations for the toml files

    Hi, I was looking at the examples. One thing I am missing is - How to exactly translate all the messages in the translate.*.toml files? For po files there are some tools like poedit. Similary do they exist for json or toml files?

  • build a

    build a "example" label

    currently label

    https://github.com/nicksnyder/go-i18n/labels

    Many people ask a question that is for getting an example, so I think to build a label for it.

📖 Tutorial: An easy way to translate your Golang application
📖 Tutorial: An easy way to translate your Golang application

?? Tutorial: An easy way to translate your Golang application ?? The full article is published on April 13, 2021, on Dev.to: https://dev.to/koddr/an-e

Feb 9, 2022
Complete Translation - translate a document to another language
 Complete Translation - translate a document to another language

Complete Translation This project is to translate a document to another language. The initial target is English to Korean. Consider this project is no

Feb 25, 2022
[UNMANTEINED] Extract values from strings and fill your structs with nlp.

nlp nlp is a general purpose any-lang Natural Language Processor that parses the data inside a text and returns a filled model Supported types int in

Nov 24, 2022
Package i18n provides internationalization and localization for your Go applications.

i18n Package i18n provides internationalization and localization for your Go applications. Installation The minimum requirement of Go is 1.16. go get

Nov 9, 2022
i18n-pseudo - Pseudolocalization is an incredibly useful tool for localizing your apps.

i18n-pseudo Pseudolocalization is an incredibly useful tool for localizing your apps. This module makes it easy to apply pseudo to any given string. I

Mar 21, 2022
Translate your Go program into multiple languages with similar fmt.Sprintf format syntax.

Loafer-i18n Loafer-i18n is a Go package and a command that helps you translate Go programs into multiple languages. Supports pluralized strings with =

Dec 22, 2021
go-i18n is a Go package and a command that helps you translate Go programs into multiple languages.

go-i18n is a Go package and a command that helps you translate Go programs into multiple languages.

Jan 2, 2023
Tool that can parse Go files into an abstract syntax tree and translate it to several programming languages.
Tool that can parse Go files into an abstract syntax tree and translate it to several programming languages.

GoDMT GoDMT, the one and only Go Data Model Translator. The goal of this project is to provide a tool that can parse Go files that include var, const,

Nov 28, 2022
Show Languages In Code. A fast and lightweight CLI to generate stats on the languages inside your project
Show Languages In Code. A fast and lightweight CLI to generate stats on the languages inside your project

slic Show Languages In Code. Usage Run it with an -h flag to list all commands. -d flag can be used to specify the directory of search -i flag can be

Dec 25, 2021
Translate Prometheus Alerts into Kubernetes pod readiness

prometheus-alert-readiness Translates firing Prometheus alerts into a Kubernetes readiness path. Why? By running this container in a singleton deploym

Oct 31, 2022
Cli tool to translate text from any language into german

GERMAN A cli tool for converting text into German. Build Locally $> go build $> go install Dependencies To execute successfully, a free tier DEEPL API

Jan 24, 2022
📖 Tutorial: An easy way to translate your Golang application
📖 Tutorial: An easy way to translate your Golang application

?? Tutorial: An easy way to translate your Golang application ?? The full article is published on April 13, 2021, on Dev.to: https://dev.to/koddr/an-e

Feb 9, 2022
May 11, 2023
URL-friendly slugify with multiple languages support.

slug Package slug generate slug from unicode string, URL-friendly slugify with multiple languages support. Documentation online Example package main

Jan 4, 2023
Stalin sort in multiple languages!

stalin-sort Stalin sort in multiple languages, contributions are welcome! Motivation This repo is motivated by this tweet, this tweet contains a refer

Jan 14, 2022
Split multiple Kubernetes files into smaller files with ease. Split multi-YAML files into individual files.

Split multiple Kubernetes files into smaller files with ease. Split multi-YAML files into individual files.

Dec 29, 2022
Split multiple Kubernetes files into smaller files with ease. Split multi-YAML files into individual files.

kubectl-slice: split Kubernetes YAMLs into files kubectl-slice is a neat tool that allows you to split a single multi-YAML Kubernetes manifest into mu

Jan 3, 2023
libraries for various programming languages that make it easy to generate per-process trace files that can be loaded into chrome://tracing
libraries for various programming languages that make it easy to generate per-process trace files that can be loaded into chrome://tracing

chrometracing: chrome://tracing trace_event files The chrometracing directory contains libraries for various programming languages that make it easy t

Oct 6, 2022
koanfenv provides koanf callbacks that translate environment variables to koanf keys.

koanfenv koanfenv provides callbacks which convert environment variables to koanf keys. These callbacks are used for env.Provider . Usage config := st

Dec 12, 2021
Translate numbers from numerals to words or roman numerals

Word-Number This package provides a methods for converting numbers to/from various 'word' representations. Currently, that means cardinal and ordinal

May 23, 2022