multilocale
v1.3.3
Published
Multilocale CLI — software localization projects, phrases, translation files and machine translation from the terminal. npx multilocale
Maintainers
Readme
multilocale
Command-line access to your translations on app.multilocale.com: projects and phrases, machine translation into every configured locale, locale rollout, cross-project phrase sharing, and translation-file download and import for web and native app codebases.
Install
npm install -g multilocale # global install
npx multilocale --help # or run without installingRequires Node.js 16 or newer.
Quick start
multilocale login # opens the browser to authorize the CLI
multilocale projects list # your projects with their ids
multilocale add "Save changes" # add a phrase, translated to every project localeFound 2 project(s):
1. example-app (64a1f2c9e4b0a1b2c3d4e5f6)
2. example-website (64a1f2c9e4b0a1b2c3d4e5f7)
en: Save changes
es: Guardar cambios
fr: Enregistrer les modifications
Added 3 phrases: https://app.multilocale.com/projects/64a1f2c9e4b0a1b2c3d4e5f6Signing up
No account yet? Create one from the terminal — the generated password prints exactly once, and the session is stored so every other command works immediately:
multilocale signup --email [email protected] --jsonAuthentication
There are two ways in:
multilocale login # interactive: choose browser or API key
multilocale login --browser # browser flow
multilocale login --with-key # masked prompt for an API key secret
multilocale logout # clear the stored session and any stored keymultilocale login --browser starts a temporary localhost server, opens your
browser to app.multilocale.com, and receives the session tokens on the
redirect back. If the browser does not open, the login URL is printed so you
can visit it by hand. Tokens are stored in ~/.multilocale/ and refreshed
automatically when they expire.
multilocale login --with-key prompts (masked) for an API key secret, created
per project on app.multilocale.com under the project's API keys page, verifies
it against the API, and stores it in ~/.multilocale/. Alternatively export
MULTILOCALE_API_KEY=<key secret> — no login step needed, the key is read
from the environment on every command. The secret is never accepted as a
command-line argument. New keys default to read-only scopes; widen them on
the key's page before running write commands.
Precedence: a stored browser session wins over a stored key, which wins over
the environment variable — so an exported MULTILOCALE_API_KEY never silently
hijacks an interactive session.
In an interactive terminal, commands that need a session and find none start the browser login on their own. Without a terminal (agents, CI, pipes) they fail fast with exit code 1 and login instructions on stderr instead of opening a browser.
Machine-readable output
Every data command accepts --json: raw, parseable JSON on stdout, no color.
Mutations print a small result object ({ "ok": true, … }). Errors always go
to stderr with exit code 1 — as a single-line JSON object when --json is
set — and progress logs move to stderr in json mode, so stdout is exactly the
JSON result.
multilocale projects list --json
multilocale phrases get SOME_KEY --json
multilocale schema # the whole command tree as JSON
multilocale schema phrases list # one subcommand's arguments and flagsCommands
Session
multilocale login # log in via browser or API key; credentials land in ~/.multilocale/
multilocale logout # clear the stored session and any stored keyProjects
multilocale projects list # list projects with their ids
multilocale projects get [projectIdOrName] # raw JSON; all projects when omitted
multilocale projects read <projectIdOrName> # formatted single-project view
multilocale projects create <name> --locales en,es,fr --default-locale en
multilocale projects update <projectIdOrName> --paths "messages/%lang%.json"Project names are unique per organization, so commands accept a project by id
or by name interchangeably. projects create always includes the default
locale in the locale list.
projects update is the only way to set a project's paths, which import
and unused read off the project rather than off multilocale.json — and
a project's paths win over the local file, so wrong ones there silently
override local configuration. The same command repairs the nameless projects
older signups created, in one call:
multilocale projects update <projectId> \
--name my-app --default-locale en --locales en,es --paths "translations/%lang%.json"Locale handling is deliberately additive, because on the wire locales is a
complete replacement list and a careless update would drop every locale it did
not mention:
| Flag | Effect |
| ------------------ | ------------------------------------------------------- |
| --locales | adds; locales already on the project are kept |
| --remove-locales | removes; the default locale cannot be removed |
| --set-locales | replaces the list outright — every other locale is lost |
The default locale is always kept in the list. --paths (on both create and
update) takes a comma-separated list, repeated flags, or several values in a
row.
Phrases
multilocale phrases list # all phrases, grouped by language
multilocale phrases list -l fr # one language (-l/--language)
multilocale phrases list -k SOME_KEY # one key across languages (-k/--key)
multilocale phrases list --languages # only the list of languages
multilocale phrases get [key] -l fr -n 20 # raw JSON rows (-n/--limit)
multilocale add "SOME_KEY" "Some value" # add + machine-translate to all locales
multilocale add "Some value" # value defaults to the key
multilocale update "SOME_KEY" "New value" -l fr # set one language's value
multilocale delete "SOME_KEY" # delete the key's rows from the project
multilocale share "SOME_KEY" other-project # attach another project to the phraseadd creates the phrase in the project's default locale and machine-translates
it into every other configured locale; it refuses a key that already exists in
the project. update sets the exact value for one key and language (default:
the project's default locale) and clears the machine-translated flags. Phrases
can be shared across projects: update warns and changes the value for every
project sharing the key, and delete removes shared rows outright rather than
detaching the current project — check multilocale phrases get <key> first.
share attaches one or more target projects (by id or name) to every locale
row of an existing phrase; --project selects the source project. The targets
receive only the locales the source phrase has.
Locale rollout
multilocale localize fr,de,ja # add locales and translate every phrase into them
multilocale localize all # every supported localeAdds the locales to the project, then machine-translates every existing phrase into them. Interruptions are safe: a re-run translates only what is still missing.
Translation files
multilocale download # write dictionary files into the working tree
multilocale download --format esm --extension js
multilocale download --nested # write nested JSON instead of flat dot paths
multilocale download --header "/* generated */" --post-script "prettier --write translations/"
multilocale import # upload existing local translation filesdownload detects the project type from the working directory:
- Android (an
AndroidManifest.xmlis present): writesres/values-<locale>/strings.xmlper language, with Android's escaping rules applied. - Everything else: writes one file per locale at the project's configured
paths(with a%lang%placeholder), defaulting totranslations/<locale>.json— or<locale>.lproj/Localizable.stringsfor theswiftformat.
| --format | Output | Default --extension |
| ---------- | ------------------------------- | --------------------- |
| json | plain JSON object | json |
| esm | export default { … } | js |
| js | module.exports = { … } | js |
| cjs | module.exports = { … } | js |
| swift | Apple .strings key/value file | strings |
import is the reverse, for onboarding an existing codebase: it reads the
Android strings.xml files or the JSON dictionaries matching the project's
paths, uploads them as phrases, and machine-translates keys missing from some
configured locales. Import once per codebase — re-importing creates duplicate
rows rather than merging.
Phrases are flat key/value pairs, so nested and namespaced dictionaries are
flattened into dot paths on import — {"checkout":{"failed":"…"}} becomes the
key checkout.failed. A literal dot inside a key is escaped (checkout\.failed)
so it cannot be confused with the separator. Values that cannot be a phrase —
arrays, null, empty objects — are reported and skipped rather than uploaded.
Pass --no-flatten to refuse a nested file instead of flattening it.
Nested output
download writes those dot-path keys back out flat, which is what a runtime
like next-intl reads. If yours expects the nested shape instead — react-i18next
namespaces, vue-i18n, Lingui nested ids — ask for it:
multilocale download --nested # {"checkout": {"failed": "…"}}
multilocale download --no-nested # flat dot paths (the default)or set it once, for every locale and every run:
{ "projectId": "…", "nested": true }The flag wins over multilocale.json, and flat is the default. The shape is
never inferred from the files already on disk: download creates those files,
so a locale that has no file yet — every locale but one, right after
projects create — would come out in a different shape from the rest.
With --nested the round trip closes: import then download reproduces the
dictionary you started from, escaped dots and all. Keys that cannot be nested
because another key already occupies their path (settings next to
settings.title) keep their flat key and are listed as they are written; no
value is ever dropped. Android strings.xml and Swift .strings are flat
file formats, so the flag is reported as ignored there.
Audits
multilocale duplicates # keys sharing the same default-language value
multilocale unused # keys not referenced in any local source fileunused scans JavaScript sources (.js, .jsx, .ts, .tsx, .cjs,
.mjs) for each key; keys assembled dynamically at runtime will look unused,
so treat the output as candidates. Android projects are not supported yet.
Skills
multilocale skills list # names and descriptions of the bundled agent guides
multilocale skills get multilocale # print a bundled SKILL.md to stdoutSchema
multilocale schema # the whole command tree as JSON
multilocale schema projects create # one command's arguments and flagsMachine translation
add and localize accept -m/--model to pick the translation model:
gpt-5.6-luna (default), gpt-5-mini, gemini-3.5-flash, or
claude-haiku-4-5. add also accepts -c/--context — a free-text hint
passed to the model. For short or ambiguous UI strings, always pass the
product domain, what the word means there, and the UI role; an isolated
two-word string routinely machine-translates to the wrong sense.
multilocale add "Max guests" \
--model gpt-5-mini \
--context "Hotel software; the maximum number of guests a room sleeps, not software users"Configuration
A multilocale.json anywhere under the working directory supplies the default
project:
{ "organizationId": "…", "projectId": "…" }When it is missing, commands list your projects, ask which one to use, and
write the file for next time. --project <idOrName> overrides it per
invocation. The same file can also hold download defaults: format,
extension, header, postScript, nested (a boolean — see nested
output), and paths (an array of file patterns containing
%lang%).
Usage with AI agents
Install the Multilocale agent skills — multilocale (this CLI) and
localization-workspace (the MCP-based localization workflow) — for Claude
Code, Cursor, Codex, and any other agent that supports the Skills standard:
npx skills add multilocale/skillsThe same guides ship inside the npm package, version-matched to the installed CLI:
multilocale skills list # what is bundled
multilocale skills get multilocale # the CLI guide matching this versionOr paste this into your AGENTS.md / CLAUDE.md:
## Translations
Use the `multilocale` CLI for translation management: adding and fixing
phrases, locale rollout, and translation-file download/import on
multilocale.com. Run `npx multilocale skills get multilocale` for the full
guide, and `multilocale --help` for the command reference. Log in once with
`multilocale login`.Prefer a connector? The Multilocale MCP server at
https://mcp.multilocale.com/mcp exposes the same data as tools for Claude,
ChatGPT, and any MCP-capable host — see
multilocale.com/developers.
