Skip to content

Internationalization

This document is for contributors and translators.

Public API usage is covered in i18n/doc.go; avoid duplicating info across both files.

Primer for translators

If you only want to translate strings without touching code, use Codeberg’s Weblate:

Placeholders and formatting

  • Translations may contain placeholders like {{.Name}}.
  • Keep these placeholders exactly as written, including the curly braces and the dot.
  • You can freely reorder placeholders within the translated text.
  • Example: {{.Count}} items selected can become 選択されたアイテム: {{.Count}} in Japanese.
  • Do not include HTML, write plain text.

Formatting uses Go's text/template package. Digits and number separators are not localised automatically.

Style tips

  • Be clear and concise, match the tone of the UI.
  • Prefer consistent terminology across the app. TODO: Create a catalogue for this purpose.
  • If a single English word is ambiguous, ask for more context or expect a contextual variant to be added using TrC or TrNC, for example context menu versus status.

Extraction workflow

We use a Go AST-based extractor. Make sure to regenerate templ code before extracting.

Developer commands via build.sh:

Text Only
1
2
3
./build.sh i18n_extract    # generate POT template
./build.sh i18n_merge      # merge POT into all locale PO files
./build.sh i18n_validate   # validate PO files with msgfmt

Typical flow:

  1. Regenerate templ code and the POT: ./build.sh i18n_extract
  2. Merge into all locales: ./build.sh i18n_merge
  3. Validate: ./build.sh i18n_validate
  4. Commit changes to the POT and any updated PO files.

Gitlab CI TODO

  • Add a job that:
  • Runs ./build.sh i18n_extract and fails if it produces a git diff to the POT.
  • Runs ./build.sh i18n_merge and ./build.sh i18n_validate.
  • Commits updated PO files in a separate MR?
  • NOTE: Ensure gettext tools msgmerge and msgfmt are available in the runner image.

Notes

  • We intentionally do not compile or load .mo files. Parsing .po is sufficient and keeps the build simpler. If we later measure performance issues attributable to .po parsing, we can revisit.
  • Tag translations for user-generated content live in i18n/data/tag_translations.yaml and are surfaced via i18n.TrTagName. They are intentionally separate from UI message catalogues and may move to another package later.

References

gettext format:

  • https://docs.weblate.org/en/latest/formats/gettext.html#example-files
  • https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
  • http://ftp.twaren.net/Unix/GNU/old-gnu/Manuals/gettext-0.11.2/html_node/gettext_9.html

templ guides:

  • Implicit ctx context.Context variable: https://templ.guide/syntax-and-usage/context/
  • Implicit children templ.Component variable: https://templ.guide/syntax-and-usage/template-composition/#children
  • templ.NopComponent: https://pkg.go.dev/github.com/a-h/templ#pkg-variables