easyi18n_cli 0.11.0 copy "easyi18n_cli: ^0.11.0" to clipboard
easyi18n_cli: ^0.11.0 copied to clipboard

Command-line tool for easyi18n. Pulls translated localization files (Mode A, native .arb) and pushes your tr() source strings for translation.

easyi18n_cli #

pub package

Command-line tool for easyi18n. Mode A (native .arb). It pulls the translated localization files from your project's published version and writes them to disk, so you keep using stock Flutter localization (flutter_localizations + gen-l10n + AppLocalizations). No runtime dependency, no hot-update. "we're your TMS".

For live hot-update (Mode B), use the easyi18n runtime SDK instead. The two are independent; pick per project.

Install #

Flutter project: add as a dev dependency (it never ships in your app):

dart pub add dev:easyi18n_cli
dart run easyi18n_cli:easyi18n pull

Non-Flutter / CI: activate globally:

dart pub global activate easyi18n_cli
easyi18n pull

Usage #

1. Configure #

dart run easyi18n_cli:easyi18n init --project-id <your-project-id>

This writes easyi18n.yaml:

projectId: proj_abc123
baseUrl: https://api.easyi18n.com   # override for the local emulator
format: arb                          # arb, json, nested_json, po, ...
output: lib/l10n                     # your l10n.yaml arb-dir

output: is a directory, for the formats that render one file per locale. A format that renders a single file holding every language — today an iOS String Catalog — names that file instead, with catalog:, and it is the one the commands read and write:

format: xcstrings
catalog: MyApp/Localizable.xcstrings   # the file your project already has

An unknown setting is reported rather than ignored, so a typo (ouput:) can't quietly leave a run on a default.

2. Authenticate #

The CLI never stores a credential. Provide a project API key (eik_…) with the read scope via the environment (or --token):

export EASYI18N_TOKEN=eik_xxxxxxxx

Create an API key in your project settings.

3. Pull #

dart run easyi18n_cli:easyi18n pull
flutter gen-l10n

pull downloads every locale's file for the configured format and writes them into output/, ready for gen-l10n. It records what it writes (in .easyi18n/state.json — add .easyi18n/ to your VCS ignore) and, on the next full pull of the same format and output dir, removes files the server no longer serves (e.g. a locale renamed to its canonical filename). A --lang pull never removes anything; switching format: or output: never prunes either — the stranded files of the old target are listed instead.

String Catalogs are merged, not replaced. An .xcstrings is a file two tools write, and Xcode owns most of it: the key order, the per-key metadata its extraction pass produces (extractionState, isCommentAutoGenerated), and every string you added since the last publish. pull injects the served translations into your file and re-prints it in Xcode's own style, so a pull that changed no translations is a byte-exact no-op instead of a whole-file reformat — and nothing you wrote goes missing. The trade: a pull never deletes a key either, so one removed from the project stays until Xcode's next extraction drops it. --lang is refused for this format, since a catalog holds every language in one file.

Flag Description
--token Credential (overrides EASYI18N_TOKEN).
--version Pull a specific published version (CalVer). Defaults to latest.
--lang Pull only one locale (e.g. --lang es).
--dry-run List the files that would be written without writing them.
--config Path to the config file (default easyi18n.yaml).

Push your source strings #

If your code calls tr() (via the easyi18n runtime SDK), the CLI can register and translate those strings for you. It statically scans your source tree for tr() calls (both the canonical context.tr('Welcome {name}') and the 'Welcome {name}'.tr() sugar) and sends the raw source strings to the backend, which tokenizes and translates them.

export EASYI18N_TOKEN=eik_xxxxxxxx          # needs the translate scope
dart run easyi18n_cli:easyi18n push

push is interactive by default: it previews the cost before spending any credits.

Scanned 42 file(s): 18 extractable tr() string(s).
3 new since last push:
  + "Welcome {name}"
  + "Save"
  + "Open"  (ctx: verb)
3 string(s) need translation · ~30 credit(s) (balance 1000).
Translate 3 string(s) for ~30 credit(s)? [y/N]
Flag Description
--dry-run Estimate the cost only; register and translate nothing.
--yes / -y Skip the confirmation prompt (for CI).
--max-credits N Abort if the estimate exceeds N credits (decimals allowed, e.g. 0.5; a CI guard).
--prune Drop orphaned strings from the lockfile (never deletes translations).
--lang Restrict to these target languages (repeatable).
--source-dir Directory to scan, relative to the config (default lib).
--token Credential (overrides EASYI18N_TOKEN).
--publish Wait for the fill to complete, then publish a new version (needs the publish scope). Strings whose fill failed are re-queued up to 2 times; whatever is still untranslated publishes serving the source text.
--approved-only With --publish: treat unapproved translations as missing.
--require-complete With --publish: fail instead of publishing when strings remain untranslated after the retries.

With --require-complete, a scan that finds no tr() strings fails before any request: push has no catalog snapshot with which to prove completeness. Check --source-dir for code-first projects. A Mode A project can use sync --require-complete only with a non-empty, supported single-file catalog:; canonical gen_l10n/ARB configs have no CLI completeness path, so review the dashboard or remove the flag only when publishing the remote state deliberately.

A tr(variable) or an interpolated tr('Hi $name') can't be read statically; the CLI reports it so you know it relies on runtime auto-capture instead.

easyi18n.lock #

push records the strings it registered in easyi18n.lock (commit it). On the next run, anything new is sent; strings that vanished from your code are reported as orphans (their translations are kept; pass --prune to drop them from the lockfile).

Apply source-verify fixes #

When source review (a Pro feature) corrects one of your base strings, the old tr('…') literal in your code is retired. apply fetches that "update your code" list and rewrites the literals for you, AST-aware:

dart run easyi18n_cli:easyi18n apply           # preview the changes
dart run easyi18n_cli:easyi18n apply --write    # apply them to disk

It's local and free (no credits) and reversible through git — review the diff, then push, and the entries reconcile automatically. Only the string literal is touched; quotes, ctx:, and formatting are left intact. A change whose call site uses a variable or interpolation (or that you already updated) is reported as unmatched, never silently changed.

Flag Description
--write Apply the rewrites to disk (default is a preview only).
--source-dir Directory to scan and rewrite, relative to the config (default lib).
--token Credential with the read scope (overrides EASYI18N_TOKEN).
--config Path to the config file (default easyi18n.yaml).

extract: inspect without pushing #

dart run easyi18n_cli:easyi18n extract

extract runs the same scan but stays offline and read-only: it prints what would be registered, what's new, what's orphaned, and which calls are dynamic. Use --fail-on-orphans as a CI drift check.

rollback: undo a bad publish #

dart run easyi18n_cli:easyi18n rollback            # restore the previous version
dart run easyi18n_cli:easyi18n rollback 2026.07.08.2

Restores a prior published version as a new version (history is never rewritten) and points delivery at it. Needs the publish scope.

Doctor: check the whole integration #

dart run easyi18n_cli:easyi18n doctor

doctor is read-only and never spends credits. It checks:

  • Local wiring — easyi18n.yaml, the easyi18n dependency, the assets/easyi18n/ offline floor, com.apple.security.network.client in BOTH macOS .entitlements (without it, delivery fetches fail silently in the sandbox), and that Easyi18nScope is mounted.
  • ICU health — lints every extracted tr() string (unbalanced braces, plural/select without other, …). A malformed ICU string renders raw to your users.
  • Delivery — actively fetches the public manifest (the runtime swallows delivery errors by design, so doctor must not): reachable, CORS served for web, and then grades your tr() scan against the published bundles — missing (never pushed/published), untranslated per locale, and unused published keys.

Exit code 1 on blocking problems; warnings (e.g. strings pending a push) don't block. Most local failures are fixed by re-running easyi18n init.

CI #

Pull translated files:

export EASYI18N_TOKEN=$EASYI18N_TOKEN   # CI secret
dart run easyi18n_cli:easyi18n pull
flutter gen-l10n

Or push on merge (register + translate, with a spend guard):

export EASYI18N_TOKEN=$EASYI18N_TOKEN   # needs the translate scope
dart run easyi18n_cli:easyi18n push --yes --max-credits 500
0
likes
140
points
449
downloads

Documentation

API reference

Publisher

verified publisherliontude.com

Weekly Downloads

Command-line tool for easyi18n. Pulls translated localization files (Mode A, native .arb) and pushes your tr() source strings for translation.

Repository (GitHub)
View/report issues

Topics

#i18n #l10n #translation #cli #arb

License

MIT (license)

Dependencies

analyzer, args, crypto, http, path, unorm_dart, yaml

More

Packages that depend on easyi18n_cli