The object-form go-i18n JSON ({"key":{"other":...}}) is parsed by Weblate's
go-i18n-json-v2 format, not go-i18n-json (which expects a top-level array).
4.4 KiB
Translating Tane (Weblate)
Runbook for the translation setup. Written so another agent (or a human) can reproduce it without prior context.
Tane is translated on translate.comunes.org/projects/tane
(a self-hosted Weblate 5.x, docker-compose at /data/weblate on host tesla).
The links to the repo and to Weblate are shown both on the landing site
(site/config.toml → sourceURL, weblateURL) and inside the app (About screen).
What is translatable
| Surface | Files | Format | Base locale | Locales today |
|---|---|---|---|---|
App (app component) |
apps/app_seeds/lib/i18n/*.i18n.json |
JSON nested (slang, {param} placeholders) |
en |
en, es, pt, fr, de, ast, ja |
Site (site component) |
site/i18n/*.json |
go-i18n JSON ({"key":{"other":"…"}}) |
en |
en, es |
Only source strings live in git; app strings use slang, so strings.g.dart /
strings_*.g.dart are generated (see the slang caveat below).
Git connection
- Repo:
https://git.comunes.org/comunes/tane.git, branchmain(private Gitea/Forgejo behind Cloudflare). - Weblate must use HTTPS + an access token — SSH port 22 is not reachable
through Cloudflare, so the stored
Comunes TranslationsSSH key is unusable here. - Repository URL in Weblate:
https://<user>:<token>@git.comunes.org/comunes/tane.gitwhere<token>is a git.comunes.org access token with read + write oncomunes/tane(Weblate pushes translations back). Generate it in Gitea/Forgejo → Settings → Applications.
The app component (create once)
The tane project already exists on Weblate. Add a component (admin UI
Add new translation component, or docker exec weblate-weblate-1 weblate shell):
| Field | Value |
|---|---|
| Project | tane |
| Name / slug | app |
| Source code repository | https://<user>:<token>@git.comunes.org/comunes/tane.git |
| Repository branch | main |
| File mask | apps/app_seeds/lib/i18n/*.i18n.json |
| Monolingual base language file | apps/app_seeds/lib/i18n/en.i18n.json |
| Template for new translations | apps/app_seeds/lib/i18n/en.i18n.json |
| File format | JSON nested structure (json-nested) — not flat json |
| Source language | English (en) |
Weblate auto-discovers the existing locales from the mask. Leave push-on-commit on
so translations flow back to main.
Sanity check after creating it:
docker exec weblate-weblate-1 weblate shell -c \
'from weblate.trans.models import Project; \
print(Project.objects.get(slug="tane").component_set.count())' # expect 1
Then edit a test string in the UI and confirm a commit lands on
git.comunes.org/comunes/tane (main) — that validates the token has write.
slang regeneration caveat (important)
Weblate only edits the *.i18n.json sources. The committed strings.g.dart /
strings_*.g.dart are generated and go stale on every Weblate commit, and
there is no CI to regenerate them. Before a release, a maintainer must:
git pull
cd apps/app_seeds && dart run slang # regenerates strings*.g.dart
cd ../.. && dart analyze # workspace gate
git add -A && git commit -m "chore(i18n): regenerate slang after Weblate sync"
(Adding a new source string manually? Same steps — edit en.i18n.json first, then
regenerate. fallback_strategy: base_locale means locales missing a key show the
English text until translators fill it in.)
The site component (landing page)
The Hugo landing strings live in site/i18n/*.json. Weblate has no native Hugo-TOML
format, so these were converted from TOML to go-i18n JSON ({"key":{"other":"…"}})
— a shape Hugo 0.140 reads identically and Weblate supports natively. Component settings:
| Field | Value |
|---|---|
| Project | tane |
| Name / slug | site |
| Source code repository | (link to the app component: weblate://tane/app) |
| Repository branch | main |
| File mask | site/i18n/*.json |
| Monolingual base language file | site/i18n/en.json |
| Template for new translations | site/i18n/en.json |
| File format | go-i18n v2 JSON (go-i18n-json-v2) |
| Source language | English (en) |
Linking the repo to the app component (weblate://tane/app) shares one clone/token.
No slang step here — Hugo consumes the JSON directly. Only EN/ES today; adding a locale =
add site/i18n/<code>.json.