Skip to main content

Command Palette

Search for a command to run...

Using `language_helper` And `AI` To Localize Flutter Apps Automatically

Updated
5 min read

1. Add language_helper to your project

dependencies:
  language_helper: ^latest_version

dev_dependencies:
  language_helper_generator: ^latest_version

2. Initialization

final languageHelper = LanguageHelper.instance;

main() async {
    WidgetsFlutterBinding.ensureInitialized();
    
    // Placeholder during development — this will be updated later.
    await languageHelper.initial([]); 

    runApp(const App());
}

3. Wrap your app

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return LanguageBuilder(
      builder: (context) {
        return MaterialApp(
          localizationsDelegates: languageHelper.delegates,
          supportedLocales: languageHelper.locales,
          locale: languageHelper.locale,
          home: const HomePage(),
        );
      }
    );
  }
}

4. Add .tr to your widget

// Simple translation
Text('Hello World'.tr)

// With parameters
Text('Hello @{name}'.trP({'name': 'John'}))

// With conditions
Text('You have @{count} item'.trP({'count': itemCount}))

5. Generate the data

a. Add the configurations to pubspec.yaml:

language_helper:
    languages: en,vi
    ignore-todo: en  # Skips TODO for `en`

b. Run the generator:

dart run language_helper:generate

6. Update the initialization

- await languageHelper.initial([]); 
+ await languageHelper.initial(
+    [LanguageDataProvider.lazyData(languageData)]
+ ); 

7. Using AI to translate

Create a new promt with the following content (at the end of the page) and execute this request

/translate-language-helper `lib/languages/data`

It’s done. The only thing left is to review the generated language data.

Read more at language_helper on pub.dev .

Prompt

You should update the prompt to ensure it matches your project and coding style.

  ---
  name: translate-language-helper
  description: translate only the *values* in a `Map<String, dynamic>` used for localization. Do **not** change keys, structure, or comments.
  ---

  ## Preflight

  1. Read the entire input file to understand context before translating any entries.
  2. If the target language is not English and the keys are not in English, check for an `en.dart` in the same folder and use it as a contextual reference.

  ## Which items to translate

  3. **Translate only values that have a `TODO` comment immediately above them.** Leave all other values unchanged.
  4. Preserve all comments (`//`, `///`) exactly as they are. Do not translate comments or modify their position. Do not translate nested comments.

  ## Keys, structure, and safety

  5. Never modify keys, the map structure, or comment text/placement. Ensure indentation and syntax remain valid Dart.
  6. After translating a value, remove the `TODO` note associated with that value (but keep surrounding comments intact).

  ## Plural handling

  7. If a value represents plural text, convert it into a `LanguageConditions` object using the `param` used in the string (e.g., `count`).
  8. Use this pattern for English plurals unless a language-specific rule is required:

    * `0` → `no products`
    * `1` → `1 product`
    * `other` (fallback) → `@{count} products`
  9. For languages that do not distinguish singular/plural in the same way, you **may** keep a single string value rather than `LanguageConditions`. Use `LanguageConditions` only when the target language requires multiple forms.

  ## Quality and style

  10. Try to keep translated text length similar to the original for layout/UX consistency (preferred, not mandatory).
  11. Produce natural, context-appropriate translations — prefer idiomatic phrasing over literal word-for-word translation when context suggests it.
  12. Preserve the original uppercase/lowercase intent of each source string in the translated value (e.g., ALL CAPS stays ALL CAPS, Title Case stays Title Case, lowercase stays lowercase), unless the target language has a clear grammatical exception.
  13. Double-check grammar, punctuation, interpolation markers (e.g., `@{count}`), escape sequences, and casing consistency so the resulting Dart file stays valid.

  ## Automation / workflow rules

  14. Do not prompt the user for permission or confirmation; perform the translation using best effort. Do not stop prematurely — continue translating until every `TODO` value in the input file has been translated and all corresponding `TODO` markers have been removed. If you encounter transient errors or rate limits, retry and resume work until the translation pass is fully complete.
  15. After finishing the translation pass, include a short summary note that describes:
      * Any ambiguous entries and the choices you made.
      * Where plural handling was applied and why.
      * Any entries left unchanged (and the reason).
  16. Run a final syntactic check to ensure the map remains valid Dart and that all TODO markers for translated values were removed.

  ---

  ## Plural example

  **Input**

  ```dart
  // TODO
  '@{count} sản phẩm': '@{count} sản phẩm'

Output (English)

'@{count} sản phẩm': LanguageConditions(
  param: 'count',
  conditions: {
    '0': 'no products',
    '1': '1 product',
    '_': '@{count} products',
  },
)

(If the target language does not require distinct plural forms, replace the value with a single translated string instead of LanguageConditions.)


Quick checklist (use at the end of each file)

  • Only values with TODO were translated.
  • Keys, structure, and comments unchanged.
  • All TODO markers removed for translated entries.
  • Plural forms converted to LanguageConditions when needed.
  • Interpolations (e.g., @{count}) preserved correctly.
  • Uppercase/lowercase intent of original strings preserved in translated values.
  • Short summary note added describing ambiguous choices and plural handling.
  • File compiles / is syntactically valid Dart (basic check).

More from this blog

Lam Nhan

5 posts