How localization works in Ditto
- A locale is a variant with a locale code (
de-DE,fr,es-419); every text item and library component carries base text plus its variants. Definitions: Variants and locales. - The base locale is the language of your base text. Set it in a project’s or the library’s Variant & locale settings if your source copy is not English.
- Locale-scoped style guides apply when text is written or translated for that locale; variables and plurals carry into every variant.
Step 1: add the locales you need
Pick one:- In the Ditto app: open Variants in the left sidebar, click + New variant, enter a name, choose the locale, and click Create Variant.
- From your agent: “Create variants for German (de-DE) and Brazilian Portuguese (pt-BR).” The agent calls
create_variantswith alocaleCodefor each. Read the developer IDs off the response; they are generated from the name unless you pass one. - From the API:
POST /v2/variantswithnameandlocaleCode. See Create variants.
Step 2: get the translations
Choose the workflow that fits your team; they can be combined.- Magic Translate (in Ditto)
- Crowdin or Lokalise
- Your own translators or pipeline
Ditto’s AI translation uses the variant’s locale code as the target and applies any style guide scoped to that locale.
- One text item: select it, open its variant tab, click Add variant, choose the locale variant, and click Translate under the text.
- A whole project: open the project’s … menu, choose Variant configuration, add the locale variants, turn on auto-translate for the ones you want translated automatically, and click Save.
- The component library: the same Variant configuration flow from the library.
Step 3: pull localized files into your app
The CLI writes one file per variant per source into./ditto by default: {project_id}___{variant_id}.{ext} for each project and components__{variant_id}.{ext} for the component library, where variant_id is the variant’s developer ID or base. Configure what to pull in ditto/config.yml at the repo root and run:
Choose a format
The same formats are available from the API without the CLI:
GET /v2/textItems/export?format=<json_i18next | json_vue_i18n | json_icu | arb | ios-strings | ios-stringsdict | android>&variantId=<variant-developer-id> and the equivalent /v2/components/export. See Export text items.
Example: a web app with three locales
type: module in the output to get ES module syntax instead of CommonJS.
iOS and Android
iosLocales and androidLocales map variants to platform locale directories: .lproj bundles with a Ditto.swift helper on iOS, values-<locale>/ resources on Android. Complete configs for both are under Examples.
Full option reference: CLI configuration (variants, iosLocales, iosLocalesOutDir, androidLocales, androidLocalesOutDir, outputs) and Files.
Keep it in sync
- Run
pullin CI or a pre-build step so every build ships the latest approved text. SetDITTO_TOKENas a secret; see CLI authentication. - Use the GitHub Action to open a pull request automatically when text changes.
- Filter by status (
statuses: [FINAL]) or by the integrated flag so unreviewed translations never reach production. Seestatusesandintegrated. - Subscribe to
TextItem_Variant_Text_ChangedandTextItem_Variants_Changedwebhooks to react when translations change.
Ask an agent to do it
With the MCP connected, all of the above is available as a conversation:create_variants, list_variants, update_text_items (with the variant developer ID) or leaves translation to Magic Translate, suggest_edit against the locale-scoped guide, and then edits the config file in your repo.