Localization
Platform → Localization turns interface translation into an ordinary annotation project: one click creates a project seeded with every English interface string, translators and reviewers work it like any other project, and Publish live compiles the approved translations into a language users can pick immediately — no rebuild, no redeploy.
Visible to Platform staff (is_staff or is_superuser). The same flag
gates every action on the page (create project, act on a request, publish).
Languages tab​
One card per language:
- The built-in languages that ship in the build — Yoruba, Hausa, Igbo, Swahili, Amharic (English is the source and is not listed).
- Any other language that already has a translation project (for example one created from a volunteer request, or added via + Add language).
A card reads Not started yet until a project exists, then shows
translated / total strings — translated is the project's finished-task
count, so it reflects submitted work, not approved work.
| Action | Effect |
|---|---|
| Create project | Creates the translation project for that language and opens it |
| Open | Jumps to the existing project |
| Publish live | Compiles the approved translations and makes the language selectable (see Publish live) |
| + Add language (title row) | Same as Create project, for a language that isn't listed — name required, code optional |
What "Create project" builds​
- A project titled
Localize AfriAnnotate → <Language>in your active organization, created by you. - One task per English interface string: the English text, its dotted key,
and a friendly "where it appears" breadcrumb (e.g. Pages › Discover).
Keys under
language.*are skipped. Strings are seeded once, at creation. - A single-field labeling config: read the English, type the translation in
one required text area (one submission per task, editable). The
instructions tell translators to leave placeholders such as
{{name}}exactly as they appear. - Project visibility public, contribution mode open, join mode review, mobile allowed — so it appears in Discover and a native speaker can apply to join; a reviewer approves them before they get tasks. See Discover & joining.
- No forced interface language on the project itself — the labeling UI stays in the translator's own language while the target language is still incomplete.
Creating fails with a message if you have no active organization or if no source strings could be loaded.
From here it is a normal project: assign translators and reviewers from Project → Members, run review as usual (Review), or let volunteers join via Discover.
Requests tab​
Any signed-in user can ask for a language from the home page — Contribute a language → Request a language (also shown to users who are not in any organization yet). The form takes a language name (required), an optional code, and an optional note (up to 500 characters). A second pending request for the same language name (case-insensitive) does not stack — the existing request is returned instead.
The Requests tab appears on the Localization page only while at least one request is pending, with a count. Each row shows the language, code, the requester's note and email, and two actions:
| Action | Effect |
|---|---|
| Create project | Fulfils the request: builds the same project as above (using the requested name and code), links it to the request, and opens it. Fulfilling an already-fulfilled request just returns its project. |
| Decline | Closes the request without creating anything. |
Both set the request's resolved time. Requests are not deleted; only pending ones are shown.
Publish live​
Publish live on a language card compiles that language's project and stores the result as a published locale for the language code:
- Only approved translations are included — for each task, the most recent annotation whose review state is accepted or fixed (reviewer edited then accepted). Submitted-but-unreviewed work does not ship.
- The text of the translation field becomes the string for that task's key; the result is nested exactly like the English catalogue.
- Publishing merges onto whatever is already live for that code, so a partial re-publish never drops strings published earlier; a re-translated key overwrites the previous value.
- The publish stores the language name and endonym, the published string count, the source total, which project it came from, and who published.
- If nothing is approved yet, publishing fails with Nothing to publish yet; the toast on success reports strings published and coverage.
Published languages show up automatically in every user's Account → Preferences → Language switcher, alongside the built-ins.
How it reaches users​
The web app fetches the published-locale list once at startup (the endpoint is public — the sign-in page needs its language before anyone is signed in), then each language's strings. Lookup order for any key: published string → built-in catalogue → English. A partially translated language is safe; untranslated keys never go blank. If the endpoint is unreachable (offline, older backend) the built-in catalogues are used silently.
Gotchas​
- Sessions already open don't see a new publish until the page is reloaded — locales are fetched once per app load.
- Give custom languages a code. A language added without a code publishes under a code derived from the first two letters of its name.
- The project lands in your active org. Switch organizations first if you want it hosted elsewhere.
- Approved only. A language with hundreds of submissions but no reviews publishes nothing — set up reviewers or review it yourself.
- Unpublishing isn't in the UI. Publishing merges; there is no button to remove a string or a language once live.
- Translated counts on the card are submissions, not approvals; the toast after publishing is the number that actually shipped.
What's next​
- Account settings → — where users switch interface language
- Discover & joining → — how volunteers find and join the translation project
- Review → — approving translations so they publish
- Platform admin overview → — the rest of the Platform section