otter/i18n
I18n utilities
Set up
First make sure you have some translations files
// en.json
{
"helloWorld": "Hello World",
}
// es.json
{
"helloWorld": "Hola Mundo",
}
Then read the file either at runtime or compile time and pass it to i18n.AddLocale()
Read translation files at compile time
// translations.go
package translations
import (
_ "embed"
"github.com/martinmunillas/otter/i18n"
)
//go:embed en.json
var EnJson []byte
//go:embed es.json
var EsJson []byte
func init() {
i18n.AddLocale("en", bytes.NewReader(translations.EnJson))
i18n.AddLocale("es", bytes.NewReader(translations.EsJson))
}
Read translation files at runtime
// main.go
package translations
import (
"os"
"github.com/martinmunillas/otter/i18n"
)
func main() {
file, _ := os.Open("./translations/en.json")
i18n.AddLocale("en", file)
_ = file.Close()
file, _ = os.Open("./translations/es.json")
i18n.AddLocale("es", file)
_ = file.Close()
}
You could even fetch the translations from a remote source Once you added your locales, make sure you use the i18n.Middleware()
// main.go
func main() {
// ...
_ = http.ListenAndServe(server.PortString(8080), i18n.Middleware(mux))
}
This middleware will make sure to set the user’s locale to the context, making it available with i18n.FromContext()
Locale switching
The user’s locale is determined by the otter-lang cookie but when it hasn’t been set the ‘Accept-Language’ header will be used.
The otter-lang cookie will be set only whenever the user decides to change their default locale.
The middleware will enable a /set-locale endpoint which will read the locale key from the request body and set it to the otter-lang cookie.
You can create your own locale setters but there is already a i18n.LanguageSelector component that wraps this endpoint. You can style it from css as this is a <select />
element with a “language-selector” class.
Translations usage
For the use of translations in your templ files you only need to call i18n.T() with your context and the translation key.
// hello_world.templ
templ HelloWorld() {
<h1>
@i18n.T(ctx, "helloWorld")
</h1>
}
If your translations contain raw html, for example "hello <b>world</b>"
, you can use i18n.RawT()
.
// hello_world.templ
templ HelloWorld() {
<h1>
@i18n.RawT(ctx, "helloWorld")
</h1>
}
There are also replacements available, these are super useful when the content needs further styling or dynamic content.
// en.json
{
"hello": "Hello {name}, we are {logo} and we are stoked to have you with us!"
}
// hello.templ
css logoStyles() {
color: tomato;
font-weight: 900;
font-size: 0.875em;
}
templ Logo() {
<p class={ logoStyles() }>AmazingStartup</p>
}
templ Hello(name string) {
<h1>
@i18n.T(ctx, "hello", map[string]any{
name: name,
logo: Logo(),
})
</h1>
}