Configuration#
Two things configure the CLI: the project on multilocale.com, and a
multilocale.json file in your repository.
multilocale.json#
The CLI looks for a multilocale.json anywhere under the working directory
(node_modules and build excluded) and uses the first one it finds.
{
"projectId": "your-project-id",
"organizationId": "your-organization-id",
"format": "json",
"extension": "json",
"paths": ["translations/%lang%.json"],
"header": "",
"postScript": ""
}
Fields#
| Field | Type | Description |
|---|---|---|
projectId |
string |
The Multilocale project every command defaults to |
organizationId |
string |
Written alongside projectId for reference |
format |
string |
Output format: json, esm, js, cjs, swift |
extension |
string |
File extension for translation files |
paths |
string[] |
Where translation files live, if the project has no paths |
header |
string |
Text prepended to each generated file |
postScript |
string |
Shell command to run after the download command (post-script also accepted) |
Committing this file is what keeps CI and agent runs from dropping into the interactive project picker, which needs a TTY. When it is missing and the account has exactly one project, the CLI picks that project and writes the file for you.
There is no projectName field: the CLI reads only projectId from this file.
Pass --project <idOrName> to override it for a single command.
Project paths#
paths says where a project's translation files live in your codebase. It is
what download writes to, and what import and unused read from. Each entry
uses %lang% as the placeholder for the language code:
translations/%lang%.json
src/locales/%lang%.json
messages/%lang%.json
Setting them#
Set them on the project with the CLI:
# On an existing project
multilocale projects update my-app --paths "translations/%lang%.json"
# Several locations at once
multilocale projects update my-app --paths "messages/%lang%.json,src/i18n/%lang%.json"
# Or at creation time
multilocale projects create my-app \
--locales en,es,fr \
--default-locale en \
--paths "translations/%lang%.json"
paths is a project field, not a dashboard setting — app.multilocale.com has no
form for it. Besides the CLI, it can be set over the REST API by sending paths
to PUT /api/projects/:projectId, or kept per-repository in
multilocale.json.
Which one wins#
- the project's own
paths, set withprojects update --pathsor the REST API pathsinmultilocale.json- a default:
translations/%lang%.<extension>— or%lang%.lproj/Localizable.<extension>for theswiftformat
The project's paths overrides the local file, so a repository that wants its
own layout should either leave the project's paths empty or keep the two in
agreement. A new account's first project already carries
["translations/%lang%.json"].
If a path matches nothing, import and unused print
No matching files for path … and locale … rather than failing — that message
names exactly what to fix.
Output Formats#
| Format | Description | Default extension | Example output |
|---|---|---|---|
json |
Standard JSON | json |
{ "key": "value" } |
esm |
ES module | js |
export default { "key": "value" } |
js |
CommonJS | js |
module.exports = { "key": "value" } |
cjs |
CommonJS (alias) | js |
module.exports = { "key": "value" } |
swift |
Apple .strings |
strings |
"key" = "value"; |
Reshaping the output#
The dictionaries Multilocale writes are flat, one file per locale. If your i18n
runtime wants a different shape — nested namespaces, a generated locale list, a
Lingui catalog — do it in a post-script, which runs after every download:
{
"postScript": "node scripts/normalizeMessages.mjs"
}
Keeping the reshape in a script rather than in Multilocale means the file the
CLI writes stays the file the CLI can read back with import.
Android Projects#
For Android projects, the CLI detects AndroidManifest.xml and reads/writes
strings.xml files in the standard resource layout:
res/values/strings.xml # Default language
res/values-es/strings.xml # Spanish
res/values-fr/strings.xml # French
No paths configuration is needed for Android projects.