flutter_string_extractor 2.0.0 copy "flutter_string_extractor: ^2.0.0" to clipboard
flutter_string_extractor: ^2.0.0 copied to clipboard

retracted

Dart CLI to extract Flutter localization strings into JSON. Supports GetX, Easy Localization, Intl and ARB import, preserving existing translations.

Flutter String Extractor — Flutter localization strings to JSON #

pub.dev CI License: MIT

Extract static translation strings and keys from Flutter/Dart source into a JSON catalog. Repeated runs preserve your translations and old keys by default. Dart syntax parsing handles quotes, escapes, raw strings, multiline strings, and adjacent literals, while ignoring comments.

Requires Dart 3.9 or later. No Flutter SDK is needed to run the extractor. Source files are read only; extraction does not rewrite widgets or insert translation calls.

Use it to collect GetX or Easy Localization keys, discover hardcoded Flutter text before localization, or export an ARB catalog to a JSON dictionary. It runs locally without a translation service, AI model, or API key.

Package: flutter_string_extractor on pub.dev. Source, issues, and releases: Reshail1/flutter_string_extractor on GitHub. See the support table before choosing a localization workflow.

Quick start: extract Flutter strings to JSON #

Install the published CLI and run it from your Flutter application root:

dart pub global activate flutter_string_extractor
flutter_string_extractor -s lib -o assets/translations/en.json

For this source:

Text('Welcome'.tr);
Text(tr('settings.title'));

the JSON dictionary is:

{
  "Welcome": "Welcome",
  "settings.title": "settings.title"
}

Edit the values to add translations. Subsequent runs keep translated values and add missing keys. Preview first with --dry-run.

The expanded APIs and options below describe 2.0.0. If pub.dev does not yet list that version, install a repository checkout using the instructions below.

Install from source #

From this package directory:

dart pub get
dart run bin/main.dart -s /path/to/flutter_app/lib -o /path/to/flutter_app/assets/translations/en.json

For a command usable from any Flutter project:

dart pub global activate --source path .
# Run from your Flutter application's root:
flutter_string_extractor -s lib -o assets/translations/en.json

Add Dart's pub cache bin directory to your PATH if the activated command is not found. The original library entry point and -s / -o options still work.

Supported translation patterns #

Matching uses syntax and exact method names, without resolving package imports. Calls with the same names in custom libraries are candidates too.

Approach Recognized examples
GetX 'title'.tr, .trArgs([...]), .trParams({...}), 'one'.trPlural('many', count), .trPluralParams(...)
Easy Localization 'title'.tr(), tr('title'), context.tr('title'), Text('title').tr(), const Text('title').tr()
Easy Localization plurals 'items'.plural(count), plural('items', count), context.plural('items', count), Text('items').plural(count)
Flutter Translate translate('title'), translatePlural('items', count)
FlutterI18n FlutterI18n.translate(context, 'title'), .plural(context, 'items', count); literal fallbackKey values are included
i18n_extension 'Hello'.i18n, 'One item'.plural(count)
Intl Intl.message('Hello', name: 'hello') exports "hello": "Hello"; without a literal name, an unnamed static message uses its text as the key
gen-l10n / Flutter Intl Import an ARB catalog with --from-arb for AppLocalizations, S.of(context), and similar generated APIs
Custom wrappers --function localize for localize('title') / service.localize('title'); --getter localized for 'title'.localized or 'title'.localized()

GetX plural calls include both literal singular and plural keys. Translation argument values, parameter names, and descriptions are not extracted in the default mode. Duplicate keys are combined, and conflicting named Intl messages abort the run before changing output.

References: GetX, Easy Localization, Flutter Translate, FlutterI18n, i18n_extension, Flutter internationalization.

Preview, discover, and filter #

# Preview the merged catalog; stdout contains JSON, stderr contains the summary.
flutter_string_extractor -s lib -o strings.json --dry-run

# Discover unmarked static literals such as Text('Welcome').
flutter_string_extractor -s lib -o strings.json --all-strings --dry-run

# Exclude files or directories using paths relative to the source directory.
flutter_string_extractor -s lib -o strings.json --exclude 'models/**' --exclude '**/debug_*.dart'

# Add your translation wrapper's exact method name.
flutter_string_extractor -s lib -o strings.json --function localize --getter localized

--all-strings includes static literals beyond UI text, such as URLs, test data, and translation arguments. Review the preview before using them as translations. Imports, exports, other directives, and runtime interpolation are excluded. Marked calls inside interpolated expressions are still extracted.

Build/cache directories and source symlinks are never traversed. Generated .g.dart, .freezed.dart, app_localizations*.dart, and messages_*.dart files are skipped unless you pass --include-generated.

Generated localizations and ICU messages #

Generated getters do not contain the original message text. Use the source catalog instead:

flutter_string_extractor -s lib -o strings.json --from-arb lib/l10n/app_en.arb

All message entries from that one source-locale catalog are imported, including messages not referenced in the scanned code. ARB metadata (@... and @@...) is omitted; ICU plural/select/placeholder strings are copied intact. Catalog values take precedence over identity placeholders extracted from code; existing output translations still win unless you choose --replace.

This exports a JSON dictionary, not a gen-l10n ARB file. Keep your original ARB files for their metadata and Flutter code generation. Use this same catalog route for Intl.plural, Intl.gender, and Intl.select: the extractor reports these calls rather than exporting incomplete plural or gender branches.

Computed keys, variables such as key.tr, constant references such as LocaleKeys.title.tr, concatenated expressions, and interpolated messages cannot be resolved by this syntax-only scan. They produce location diagnostics when used in recognized translation calls. Supply literals or import the source catalog; the extractor does not evaluate Dart code or guess their values.

Output and translation preservation #

For 'Hello'.tr and tr('Settings'), the initial catalog contains:

{
  "Hello": "Hello",
  "Settings": "Settings"
}

After translating Hello to Hallo, running extraction again keeps Hallo. Removed source keys remain in the output. Existing nested catalogs and plural / gender objects are preserved; newly discovered dotted keys are added inside an existing nested namespace. New catalogs use flat keys. Missing translations start as key-to-key placeholders; plural/gender placeholders need the correct structure for your localization package before use.

To explicitly reset the catalog to current extraction results:

flutter_string_extractor -s lib -o strings.json --replace

Only .json output destinations are accepted. Missing output directories are created, except in a dry run. Missing source, syntax errors, conflicting message IDs, malformed catalogs, and unsafe destinations abort before writing. Existing JSON must be an object even in replacement mode. Top-level keys are sorted.

Writes use a private temporary directory beside the destination and a same-filesystem rename, with cleanup afterward. Output symlinks, symlinked parent directories, and directory destinations are rejected. On macOS/Linux, existing POSIX access permissions are retained and new files use owner-only permissions (0600); /bin/chmod must be available. Windows uses filesystem permissions inherited from the destination directory. Replacement can change file ownership or extended ACLs; review those separately when sharing catalogs. Portable file checks do not fully prevent races with another process changing paths.

Errors and warnings go to stderr. Exit codes: 0 for a successful extraction or preview, 1 for extraction/file errors, 64 for incorrect CLI arguments. Warnings about unresolved messages do not change the successful exit code.

Options #

Option Default / behavior
-s, --src-dir lib
-o, --output-file strings.json
--all-strings Discover all static literals except directives
--dry-run Print merged JSON without modifying files
--replace Discard existing translations and old keys explicitly
--exclude Repeatable source-relative glob; quote patterns in the shell
--include-generated Include generated files; build/cache exclusions still apply
--function Repeatable translator method name; key is the first positional argument
--getter Repeatable String getter/extension method name
--from-arb Source ARB catalog to import
-h, --help Display CLI help

Library usage #

import 'package:flutter_string_extractor/flutter_string_extractor.dart';

void main() {
  final result = FlutterStringExtractor.extractStrings(
    'lib',
    'strings.json',
    dryRun: true,
    exclude: ['models/**'],
    functions: ['localize'],
    // sourceArb: 'lib/l10n/app_en.arb',
  );
  print(result.json);
  for (final warning in result.warnings) {
    print(warning);
  }
}

The result includes translations, filesScanned, extractedCount, addedCount, and warnings. Existing two-argument calls still write output.

Frequently asked questions #

How do I extract hardcoded Flutter text for localization? #

Run flutter_string_extractor -s lib -o strings.json --all-strings --dry-run. Review the JSON preview: discovery also includes URLs and other non-UI literals. Remove --dry-run when ready to write the catalog. Add translation calls to your widgets separately; the extractor keeps source files unchanged.

Can I use it with AppLocalizations or S.of(context)? #

Yes, import the source ARB file with --from-arb lib/l10n/app_en.arb. Generated getters cannot supply the original messages to a syntax-only scan. The import includes every message in that catalog and keeps ICU strings intact; it does not create a new ARB file.

Does it translate strings using AI or send my source to a server? #

No. Extraction parses local Dart files and reads local JSON/ARB catalogs. It creates translation placeholders; you provide the translated values. You do not need an AI subscription or translation API key to run it.

Does rerunning extraction overwrite my translations? #

Existing values, nested catalogs, and old keys remain by default. New keys are added. --replace explicitly discards the previous catalog after validating it.

Why was a translation key skipped? #

Check stderr for the file and line. Variables, constant references, and interpolation cannot be evaluated by this syntax-only extractor. Use literal keys or import the source catalog. Custom wrapper names can be registered with --function and --getter.

Which installed CLI version am I using? #

Run dart pub global list. To update a pub.dev installation, run dart pub global activate flutter_string_extractor again.

Development #

dart pub get
dart analyze
dart test
dart test --test-randomize-ordering-seed=421
dart format --output=none --set-exit-if-changed lib bin/main.dart test example/main.dart

Tests exercise translation APIs, Unicode/escaped literals, ARB imports, nested catalogs, CLI errors, permissions, and unsafe destinations. A seeded stress case extracts 500 messages across 20 files and checks ten subsequent writes for identical output. CI runs the suite on Linux, macOS, and Windows with Dart 3.9.0 and stable. Formatting is checked with Dart 3.9.0 to keep the formatter consistent across SDK updates. Fork pull requests receive read-only CI permissions.

Publishing releases #

The publishing workflow runs when a version tag such as v2.0.0 is pushed. It uses the official Dart reusable workflow and short-lived OIDC authentication; no pub.dev credentials belong in this public repository. Regular pushes to main run CI; publishing requires a version tag.

In the package's pub.dev admin settings, enable automated publishing from GitHub for repository Reshail1/flutter_string_extractor and tag pattern v{{version}}. This publisher setting is required separately from committing the workflow. See Dart's automated publishing guide.

After updating pubspec.yaml and CHANGELOG.md, wait for the main commit's CI checks to pass. Confirm the tag version equals the package version and has not already been published, then release it:

git tag v2.0.0
git push origin v2.0.0

For later releases, use the new package version in both commands. Restrict creation and modification of release tags to trusted maintainers in GitHub repository rulesets: the pub.dev publisher grants that repository permission to release the package. Never commit access tokens, pub credentials, or private application catalogs.

License #

MIT.

8
likes
0
points
481
downloads

Documentation

Documentation

Publisher

unverified uploader

Weekly Downloads

Dart CLI to extract Flutter localization strings into JSON. Supports GetX, Easy Localization, Intl and ARB import, preserving existing translations.

Homepage
Repository (GitHub)
View/report issues

Topics

#cli #localization #flutter #i18n #string-extraction

License

unknown (license)

Dependencies

analyzer, args, glob, path

More

Packages that depend on flutter_string_extractor