motrgem 1.0.6
motrgem: ^1.0.6 copied to clipboard
A Flutter localization tool that automatically extracts hardcoded texts from widgets and converts them to l10n format.
Motrgem - Flutter L10n Text Extractor #
A powerful command-line tool that automatically extracts hardcoded text strings from Flutter widgets and converts them to l10n (localization) format.
Installation #
Option 1: Quick Install (Recommended for Dev Dependency) #
Run this command in your Flutter project:
flutter pub add dev:motrgem
This automatically adds motrgem to your dev_dependencies and runs flutter pub get.
Option 2: Global Installation (Recommended for CLI Tool) #
Install globally to use the motrgem command anywhere:
dart pub global activate motrgem
Verify installation:
motrgem --help
Option 3: Manual Installation #
Add to your pubspec.yaml:
dev_dependencies:
motrgem: ^1.0.6
Then run:
flutter pub get
Command Usage:
- Global install:
motrgem start,motrgem --replace - Dev dependency:
dart run motrgem start,dart run motrgem --replace
Features #
This project includes a powerful L10n Text Extractor library that automatically:
- π Analyzes your Flutter code using the Dart analyzer to find hardcoded text strings in widgets
- π·οΈ Generates unique IDs for each text string in camelCase format
- π Updates ARB files with extracted texts and metadata
- π Replaces hardcoded strings with
AppLocalizationscalls - π¦ Automatically adds imports for localization files
- π Supports multiple locales with easy locale file generation
Supported Widgets #
The library extracts text from these common Flutter widgets:
TextAppBarTextButton,ElevatedButton,OutlinedButtonFloatingActionButtonTooltipSnackBar,AlertDialogListTile,ChipInputDecoration(with parameters likehintText,labelText, etc.)
Usage #
Initialize Project (First Time Setup) #
Initialize a Flutter project with l10n support:
dart run motrgem start
This command will:
- Add necessary dependencies to
pubspec.yaml(flutter_localizations, intl, analyzer, path, args) - Create
l10n.yamlconfiguration file - Create
lib/l10ndirectory - Create initial
app_en.arbfile - Enable
generate: truein pubspec.yaml
Extract texts (Dry Run) #
See what would be extracted without making any changes:
dart run motrgem --dry-run
Extract and replace #
Extract texts, update ARB file, and replace hardcoded strings in your code:
dart run motrgem --replace
flutter clean
flutter pub get
Const Keyword remove #
You should delete all const widgets which use AppLocalizations:
Before:
const Text(AppLocalizations.of(context)!.helloWorld)
Should be After:
Text(AppLocalizations.of(context)!.helloWorld)
Add a new locale #
Create a new locale file (e.g., Spanish, French, Arabic):
dart run motrgem --add-locale es
dart run motrgem --add-locale fr
dart run motrgem --add-locale ar
Note: If using as a dev dependency, prefix all commands with
dart run, e.g.,dart run motrgem start
Changing Language at Runtime #
After setting up localization, you can allow users to change the app language dynamically:
1. Make your app stateful with locale management:
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:your_app/l10n/app_localizations.dart';
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
// Static method to change locale from anywhere in the app
static void setLocale(BuildContext context, Locale newLocale) {
_MyAppState? state = context.findAncestorStateOfType<_MyAppState>();
state?.setLocale(newLocale);
}
}
class _MyAppState extends State<MyApp> {
Locale? _locale;
void setLocale(Locale locale) {
setState(() {
_locale = locale;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
locale: _locale,
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: const HomePage(),
);
}
}
2. Change language from anywhere in your app:
// Switch to Spanish
MyApp.setLocale(context, const Locale('es'));
// Switch to Arabic
MyApp.setLocale(context, const Locale('ar'));
// Switch to English
MyApp.setLocale(context, const Locale('en'));
3. Example: Language selector dropdown:
class LanguageSelector extends StatelessWidget {
const LanguageSelector({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: Localizations.localeOf(context).languageCode,
items: const [
DropdownMenuItem(value: 'en', child: Text('English')),
DropdownMenuItem(value: 'es', child: Text('EspaΓ±ol')),
DropdownMenuItem(value: 'ar', child: Text('Ψ§ΩΨΉΨ±Ψ¨ΩΨ©')),
DropdownMenuItem(value: 'fr', child: Text('FranΓ§ais')),
],
onChanged: (String? languageCode) {
if (languageCode != null) {
MyApp.setLocale(context, Locale(languageCode));
}
},
);
}
}
Getting Started #
Quick Start (New Project) #
- Create or navigate to your Flutter project
- Initialize l10n support:
dart run motrgem start
- Install dependencies:
flutter pub get
- Extract and replace texts:
dart run motrgem --replace
Prerequisites #
- Flutter SDK installed
Setup Localization #
- The project already includes
l10n.yamlconfiguration:
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
- In your
pubspec.yaml, ensure you have:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: ^0.20.2
flutter:
generate: true
- After running the extractor with
--replace, add localization delegates to yourMaterialApp:
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
// ... other properties
)
How It Works #
1. Text Extraction #
The library uses the Dart analyzer package to parse your Flutter code's Abstract Syntax Tree (AST). It identifies:
- Direct string literals in Text widgets
- Named parameters containing text (like
title:,tooltip:,label:) - Strings in various widget constructors
2. ID Generation #
Text strings are converted to camelCase IDs:
- "Hello World" β
helloWorld - "You have pushed the button" β
youHavePushedTheButton - "Sign In" β
signIn
The generator:
- Removes special characters
- Handles duplicates by appending numbers
- Ensures valid Dart identifiers
3. ARB File Management #
Extracted texts are added to lib/l10n/app_en.arb:
{
"@@locale": "en",
"youHavePushedTheButton": "You have pushed the button this many times:",
"@youHavePushedTheButton": {
"description": "Text from Text in main.dart"
}
}
4. Code Replacement #
Original code:
Text('You have pushed the button this many times:')
Becomes:
Text(AppLocalizations.of(context)!.youHavePushedTheButton)
Project Structure #
lib/
βββ main.dart # Main app file
βββ l10n/
β βββ app_en.arb # English translations
βββ src/
βββ utils/
βββ Text_extractor.dart # Core analyzer and extractor
βββ arb_manager.dart # ARB file operations
βββ l10n_manager.dart # Workflow orchestration
bin/
βββ l10n_extractor.dart # CLI tool
l10n.yaml # L10n configuration
Library Components #
TextExtractor #
Analyzes Dart files using the analyzer package to find hardcoded strings.
final extractor = TextExtractor();
final texts = await extractor.extractTextFromProject(projectPath);
ArbManager #
Manages ARB file operations (reading, writing, adding locales).
final arbManager = ArbManager(projectPath: projectPath);
await arbManager.addTextsToArb(texts);
L10nManager #
Orchestrates the complete workflow.
final manager = L10nManager(projectPath);
final result = await manager.processProject(replaceInCode: true);
Example Output #
Initialize Command #
π Initializing Flutter L10n in project...
π Setup Results:
β
Updated pubspec.yaml with dependencies
β
Created l10n.yaml configuration
β
Created lib/l10n directory
β
Created initial ARB file (app_en.arb)
β
Project initialized successfully!
π Next steps:
1. Run: flutter pub get
2. Run: dart run bin/l10n_extractor.dart --dry-run
3. Run: dart run bin/l10n_extractor.dart --replace
Extract Command #
π Flutter L10n Text Extractor
ββββββββββββββββββββββββββββββββββββββββββββββββββ
π Extracting texts from project: .
π Found 2 hardcoded text(s)
π Extracted texts:
lib/main.dart:107:24 - [Text] "You have pushed the button..." -> youHavePushedTheButton
lib/main.dart:117:18 - [FloatingActionButton.tooltip] "Increment" -> increment
π Updating ARB file...
ARB file updated: lib/l10n/app_en.arb
Added 2 text entries
π Replacing texts in code...
β
Replaced in main.dart: "You have pushed the button..."
β
Replaced in main.dart: "Increment"
π¦ Added import to main.dart
β¨ Summary:
- Texts extracted: 2
- Texts replaced: 2
π ARB Statistics:
- Total entries: 2
- With metadata: 2
ββββββββββββββββββββββββββββββββββββββββββββββββββ
β
Process completed successfully!
Advanced Usage #
Filtering Technical Strings #
The library automatically skips:
- URLs (
http://,https://,www.) - File paths
- Numbers-only strings
- ALL_CAPS constants
- Format strings (
%s,%d) - Template strings with
${}
Handling Duplicates #
When the same base ID would be generated multiple times, the library automatically appends numbers:
- First occurrence:
buttonText - Second occurrence:
buttonText2 - Third occurrence:
buttonText3
Development #
Running Tests #
flutter test
Adding New Widget Support #
Edit lib/src/utils/Text_extractor.dart and add to the textWidgets set:
static const textWidgets = {
'Text',
'YourCustomWidget',
// ... more widgets
};
Adding New Text Parameters #
Add to the textParams set in _isTextParameter():
const textParams = {
'title',
'yourCustomParam',
// ... more parameters
};
Contributing #
Feel free to submit issues and enhancement requests!
License #
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments #
- Built with the Dart
analyzerpackage - Uses Flutter's official
intlpackage for localization - Follows Flutter localization best practices