flutter_localisation_cli 1.5.0 copy "flutter_localisation_cli: ^1.5.0" to clipboard
flutter_localisation_cli: ^1.5.0 copied to clipboard

Terminal CLI (fl) and MCP server (fl_mcp) for FlutterLocalisation — add, edit, delete and AI-translate localization keys from the shell or from Claude, then pull the ARBs. Pure Dart; pairs with the fl [...]

Changelog #

1.5.0 - 2026-08-22 #

Fixed #

  • Regional and script locales are handled as one identity. Locale codes arrived as whatever was typed, so fl languages add pt_br compared pt_br against the project's pt-BR, found no match, and asked the API to create a locale that already existed. Every locale argument is now canonicalised to BCP-47 (pt_br / PT-BRpt-BR, zh_hantzh-Hant, es_419 unchanged) before it is compared or sent. Junk is passed through untouched so the API's own error still names the field.
  • The ARB uploaded by import carries the filename gen_l10n reads. A variant produced app_pt-BR.arb, which Flutter's generator does not pick up at all; it is now app_pt_BR.arb.
  • add --auto-translate no longer reports a success as a failure. The server-side fill of a large project can outlive the socket, and the retry then reached a locale the first attempt had already created. That 400 is now followed by the same verify-and-report read as the happy path.
  • A rejected request shows the server's own reason. Errors carrying error rather than message/detail printed "POST /api/... failed" while the server had said exactly what was wrong.

1.4.0 - 2026-08-20 #

Changed #

  • A value that comes back identical to its source is no longer reported as a failure. It is almost always the correct answer — "OK", "Premium", "Normal", "Start", French Nature, German Name — and calling it a failure cost more than tidiness. It trained readers to skip the number; it hid the genuine errors sitting in the same count; and because identical-to-source is retranslate's selection criterion, it left those rows queued to be re-translated and re-reported on every run for ever. translate, add, import and retranslate now report translated / failed / unchanged separately, and only a real error affects the exit code.
  • The backend's own per-row reasons are printed instead of summed. A count of failures cannot distinguish a malformed plural row from a dead service; the reason string can, and it was already being parsed and then discarded. This applies to the whole-batch rejection path too, where the detail lives in results.failed behind a top-level "All translations failed."

Added #

  • fl retranslate --accept-unchanged (accept_unchanged on MCP) marks every value that came back identical to its source as checked, which status and retranslate already honour. This is what makes the queue closable: nothing in the pipeline previously set checked, so a deliberately-identical row could never leave the work list. Reviewers can flip any of them back with fl edit --no-checked.
  • fl edit gained the plural fields: --singular-case, --plural-case, --zero-case, --two-case, --few-case, --many-case, --plural-param, --plural. The backend stores plural cases separately and rejects a --value carrying the placeholder, so a bad plural translation previously could not be repaired from the terminal at all.
  • The client models every CLDR plural category. It had zero, one (singular_case) and other (plural_case) only — no two, few or many. French, Spanish, Italian, Portuguese, Polish and Czech all require many; Polish and Czech also require few; Arabic requires two. Because the backend re-validates the whole row on any write, a row missing a category its locale requires could not be saved at all — not even an update touching nothing but is_checked. Those rows were unfixable through the CLI and unexplainable from its output, since the reason was being discarded.

Fixed #

  • import --translate no longer reports a successful import as a total failure. The import is written before the translate phase runs, so a timeout there — the likeliest outcome for a large import, and the one that actually happened with 837 keys — surfaced as a bare Error: Gateway Time-out from a run whose keys were all safely created. Nothing said the keys were in, and nothing named the one-command remedy. It now reports what was imported, what failed, and points at fl retranslate, which chunks and therefore survives what one large request does not.
  • A whole-batch 400 whose rows are all identical-to-source no longer aborts the run. "Every row in the chunk failed" is a 400 rather than a 207, and it is the normal outcome once the only gap left is loanwords — so a project in exactly that state could never complete a run, and therefore could never reach --accept-unchanged to get out of it. A rejection carrying no per-row detail is still fatal, so a genuine outage is not absorbed.

1.3.0 - 2026-07-31 #

Added #

  • fl guard now teaches, not just blocks. Alongside the .claude/settings.json deny rules, it writes an AI-guidance block into AGENTS.md and CLAUDE.md in the consuming repo, stating that the FlutterLocalisation SaaS is the source of truth and showing the correct fl add / fl edit / fl pull workflow. A bare write refusal made agents route around the guard (writing the string elsewhere); the docs turn the block into an instruction. The block is delimited by <!-- fl:guard:start/end --> markers and refreshed idempotently, so a project's own notes in those files are preserved.
  • MCP server advertises instructions on initialize. Any AI client connecting to fl_mcp now receives top-level guidance (SaaS is authoritative, never hand-edit ARBs, mutate via tools then fl pull, preview-before-apply) before it calls a tool.

1.2.1 - 2026-07-21 #

Fixed #

  • import --language <code> now writes ONLY that locale. It was sending apply_to_all_languages=true regardless, so a targeted per-locale import clobbered every other language with the file's values. A base-language import (no --language) still seeds all locales so fresh keys stay translatable.

1.2.0 - 2026-07-21 #

Added #

  • ARB @key metadata now round-trips through the API. add / fl add and add_string (MCP) gained --placeholder name:type[:format] (repeatable) and --description, so a key can be created with typed placeholders (e.g. count:int:decimalPattern) and an ICU @key.description. edit / fl edit and edit_string (MCP) gained --description. TranslationEntry now reads description + placeholders back from the backend.

Fixed #

  • edit_string (MCP) no longer drops placeholders. The edit dispatch previously omitted placeholder metadata entirely; it now forwards placeholders + is_placeholders_enabled alongside the new description.

1.1.0 - 2026-07-14 #

Fixed #

  • --translate no longer over-reports success. add / translate / import --translate trusted the backend's success_count, which counts source == output as translated (a silent false success). The CLI now re-fetches after translating and flags any locale whose value still equals its key's non-empty base text as failed, so translated N/N never lies. import --translate's failed field is now a list (matching add/translate).

Added #

  • Bulk ARB import — import_arb MCP tool + fl import CLI command. Instead of many per-key add_string / fl add calls, put all strings in an ARB JSON and import it in a single request (path to a file or inline content for the MCP tool; fl import <file.arb> for the CLI). translate=true / -t then batch-translates the other locales in one pass; overwrite/--overwrite replaces existing values; --language <code> sets the file's locale (default: base). Preview by default (apply=true / no --dry-run to write). Backed by ManagementClient.importArb() (multipart to /api/project/{id}/import-arb/) and Operations.importArb(). Requires a strings:write token.
  • fl guard command — lock the backend-managed files against AI edits. Writes permissions.deny rules into the project's .claude/settings.json so Claude Code refuses to Edit/Write the ARB directory (arb_dir + l10n.yaml arb-dir/output-dir) and lib/generated_translation_methods.dart — files that only ever change via the SaaS tooling + git pull, and whose hand-edits are otherwise silently overwritten on the next sync. Idempotent; merges into existing settings; --dry-run previews.

1.0.1 - 2026-07-14 #

Fixed #

  • fl_mcp now finds the token from fl login. It previously read only $FL_API_TOKEN and ignored ~/.config/flutterlocalisation/credentials.json, forcing users to duplicate the token into their MCP client config. It now uses the same resolution as the fl CLI (explicit → $FL_API_TOKEN → credentials file). Credentials.resolve gained an injectable credentialsFile for tests.

1.0.0 - 2026-07-07 #

Added #

  • Initial release. The fl CLI and fl_mcp MCP server, extracted from the flutter_localisation package into a standalone pure-Dart package so they can be installed and run without the Flutter SDK (dart pub global run now works, and the runtime library no longer carries CLI dependencies).
  • fl commands: login, projects, add (--translate), edit, delete, translate, status, pull; global --project, --flavor, --config, --dry-run, --json.
  • fl_mcp: stdio MCP server exposing list_projects, list_status, add_string, edit_string, delete_string, translate_key — preview-by-default (only writes with apply: true), project selection by name.
  • Auth via a scoped flk_live_ API token; project config file is optional (workspace-level commands and --project <name> work token-only).
0
likes
140
points
165
downloads

Documentation

Documentation
API reference

Publisher

verified publishertajaouart.com

Weekly Downloads

Terminal CLI (fl) and MCP server (fl_mcp) for FlutterLocalisation — add, edit, delete and AI-translate localization keys from the shell or from Claude, then pull the ARBs. Pure Dart; pairs with the flutter_localisation runtime package.

Homepage
Repository (GitHub)
View/report issues

Topics

#localization #i18n #cli #mcp

License

MIT (license)

Dependencies

args, http

More

Packages that depend on flutter_localisation_cli