Skip to main content

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.

ActionEffect
Create projectCreates the translation project for that language and opens it
OpenJumps to the existing project
Publish liveCompiles 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:

ActionEffect
Create projectFulfils 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.
DeclineCloses 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​