Hugo v0.17 has native support for internationalization. This thread discusses approaches that were used in prior versions.
Currently I’m porting the Freelancer Theme to Hugo. It’s a small single-page portfolio. I want provide the option to let the user translate each string by setting the corresponding translation or change of the text in the config file.
Is no translation set, the template renders a default string. Since the theme is not very complex I’ve to options to implement i18n:
Either I hard code them into the templates with
{{ with .Site.Params.footer.place }}{{.}}{{ else }}Place{{end}}
or I create a another translation file with all default strings that can be accessed this way:
{{ with .Site.Params.footer.place }}{{.}}{{ else }}{{ .Site.Data.translation.footer.place }}{{end}}
Then add a template func, something like message(key) that gets a resource for the given key from the resource bundle for the locale defined in config.toml or in one of its parents; if not found in any of them, it returns NOT_FOUND.
So the hiearchy goes from right to left, more specific to less, the fallback is messages.yaml (or toml, json).
If not found (NOT_FOUND) it should be logged as a warning. I’m not fan of adding a default string in the func as this will make it impossible to track missing strings.
That would be great @bep , and a wonderful way to get Hugo more traction, with a primary built-in method like that. I like how Java does it, and falling back to the default or a “NOT_FOUND” if there’s no string. I’d personally pick a default and always start there, translating after the default was added to the top-most file in the hierarchy.
Thanks for all the replies and especially to @RickCogley for providing a whole tutorial. I really appreciate the community around Hugo and the help in this forum.
This goes a bit beyound my requirements but are there also some tips for localizing the content? Hugo provides already a way of formating dates with a template function as far as I’ve seen it in the docs. But is there a way to do this nore dynamically depending on the language?
Other aspects of l10n is the formating of currencies etc that need to kept in mind. Are there also some best practices to recommend?
Agree, it’s a great community and I want to participate somehow to make it better.
I see what you mean about other locale localizations. I think I read somewhere that go itself was not yet fully localized (iirc I had searched on making Japanese dates appear correctly), so it was a challenge to make that sort of thing happen with Hugo. The actual developers will know more, for sure.
The more I read and think about i18n the more I’m convinced the core support should be in Go’s stdlib. It’s in their plans, but they haven’t gotten there yet.
@RickCogley, I saw in your ‘pull requested’ tutorial, that you use a lot of ifs. This would result in a lot of template code for each string.
I think the implementation of a function that takes the key and returns the corresponding translation for the current language is much more elegant, as shown by @bep. This would be a nice feature that could be implemented by the Hugo devs. It’s just my opionion for the general use of i18n.
Back to my much smaller needs. Currently I’m using a config.yaml that that stores all strings under params like this:
portfolio:
title: Portfolio
modal:
client: Client
date: Date
category: Category
button:
text: Close
My template looks if the string is set. Otherwise it renders the default text. This isn’t very elegant since my templates look a bit cluttered.
I also need to support only one language or any other custom string the user wants to see. Knowing this, I can outsource the translations from my config file into its file. Beside exists a file with all default strings.
The tutorial is nice for larger i18n needs (kudos for that) but I just need to generate a single version of my theme that either shows a custom string or the default one.
go-i18n seems to be a nice package. The developer just needs to insert T("A string to translate") in the code. It uses the key approach of @bep. All translations are stored inside .json files. This creates a small file format limitation.
But making the T() function available as template function would give a nice approach to do i18n – regardless of the project size.
The tutorial I wrote shows both the use of ifs to show a block of text based on locale, or, how to pull from a data file. In my opinion, you need to use ifs if you have complex formatting needs, like grammar changes based on language, or, inline formats (like if you want part of a translated string formatted in an <em>, say), which don’t survive being pulled from a data file at this time. And, you can use the data file pull if it’s just simple strings with no formatting.
Native and more-well-developed methods would be nice, but if those are a necessity, they are not yet available as far as I know.
@RickCogley If you translate a page like in the tutorial you wrote, do you insert just the translation or also the rest of the configuration ( like title, baseurl, theme)?
Your deployment scripts runs every config file independently. So this information are required for Hugo to build the site.
The tutorial just shows one part. That’s the basic idea though, and you’d weave those techniques in, for your index, single, or other templates. I’m using both techniques in every template, mostly.