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#

  1. the project's own paths, set with projects update --paths or the REST API
  2. paths in multilocale.json
  3. a default: translations/%lang%.<extension> — or %lang%.lproj/Localizable.<extension> for the swift format

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.