Modular Flutter Localization
Organize your Flutter translations by feature/module for better scalability and reusability.
✨ Features
| Feature |
Description |
| 📦 Modular Organization |
Keep translations alongside your feature code |
| 🔄 Auto-Generation |
Watch mode regenerates code on file changes |
| 🌍 RTL Support |
Full support for Arabic, Hebrew, and other RTL languages |
| 🧩 Reusable Modules |
Copy feature folders between projects with translations included |
| 📝 Type-Safe |
Generated Dart code with full IDE autocompletion |
| 🎯 Nested Access |
Clean API: S.auth.email instead of flat keys |
| 🔢 Pluralization |
Full ICU message format support |
🚀 Quick Start
1. Install the Extension
Install from the VS Code Marketplace or search for "Modular Flutter Localization" in VS Code.
2. Create Your First Module
Create ARB files in your feature folder:
lib/features/auth/l10n/
├── auth_en.arb
└── auth_ar.arb
auth_en.arb:
{
"@@locale": "en",
"@@context": "auth",
"email": "Email",
"password": "Password",
"login": "Login",
"welcomeBack": "Welcome back, {name}!"
}
auth_ar.arb:
{
"@@locale": "ar",
"@@context": "auth",
"email": "البريد الإلكتروني",
"password": "كلمة المرور",
"login": "تسجيل الدخول",
"welcomeBack": "مرحباً بعودتك، {name}!"
}
3. Generate Code
The extension will auto-generate on save (if watch mode is enabled), or use the command palette:
- Press
Ctrl+Shift+P (or Cmd+Shift+P on macOS)
- Type "Modular L10n: Generate Translations"
- Press Enter
4. Use in Your App
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'generated/l10n/l10n.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
locale: const Locale('en'),
supportedLocales: S.supportedLocales,
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
home: const LoginScreen(),
);
}
}
class LoginScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
// Access translations with type-safe nested syntax
TextField(decoration: InputDecoration(labelText: S.auth.email)),
TextField(decoration: InputDecoration(labelText: S.auth.password)),
ElevatedButton(
onPressed: () {},
child: Text(S.auth.login),
),
// With parameters
Text(S.auth.welcomeBack('Ahmed')),
],
),
);
}
}
📁 Project Structure
your_flutter_app/
├── lib/
│ ├── features/
│ │ ├── auth/
│ │ │ ├── l10n/
│ │ │ │ ├── auth_en.arb ← English translations
│ │ │ │ └── auth_ar.arb ← Arabic translations
│ │ │ ├── screens/
│ │ │ └── widgets/
│ │ ├── home/
│ │ │ ├── l10n/
│ │ │ │ ├── home_en.arb
│ │ │ │ └── home_ar.arb
│ │ │ └── ...
│ │ └── settings/
│ │ ├── l10n/
│ │ │ ├── settings_en.arb
│ │ │ └── settings_ar.arb
│ │ └── ...
│ └── generated/
│ └── l10n/ ← Generated code (don't edit)
│ ├── s.dart
│ ├── auth_l10n.dart
│ ├── home_l10n.dart
│ └── settings_l10n.dart
⚙️ Configuration
Add to your .vscode/settings.json:
{
"modularL10n.outputPath": "lib/generated/l10n",
"modularL10n.supportedLocales": ["en", "ar"],
"modularL10n.defaultLocale": "en",
"modularL10n.arbFilePattern": "**/l10n/*.arb",
"modularL10n.watchMode": true,
"modularL10n.generateCombinedArb": true,
"modularL10n.className": "S"
}
| Setting |
Default |
Description |
outputPath |
lib/generated/l10n |
Where to generate Dart files |
supportedLocales |
["en", "ar"] |
List of locale codes to support |
defaultLocale |
en |
Fallback locale |
arbFilePattern |
**/l10n/*.arb |
Pattern to find ARB files |
watchMode |
true |
Auto-regenerate on file changes |
generateCombinedArb |
true |
Create combined ARB files |
className |
S |
Name of main localization class |
🛠️ Commands
| Command |
Description |
Modular L10n: Generate Translations |
Regenerate all translation files |
Modular L10n: Add Translation Key |
Add a new key to a specific module |
Modular L10n: Create New Module |
Create a new feature module with l10n scaffold |
Basic String
{
"greeting": "Hello"
}
With Description
{
"greeting": "Hello",
"@greeting": {
"description": "Simple greeting shown on home screen"
}
}
With Placeholders
{
"welcomeMessage": "Welcome, {name}!",
"@welcomeMessage": {
"description": "Welcome message with user name",
"placeholders": {
"name": {
"type": "String",
"example": "John"
}
}
}
}
With Pluralization
{
"itemCount": "{count, plural, =0{No items} =1{1 item} other{{count} items}}",
"@itemCount": {
"description": "Number of items in cart",
"placeholders": {
"count": {
"type": "int"
}
}
}
}
Usage:
Text(S.home.itemCount(0)) // "No items"
Text(S.home.itemCount(1)) // "1 item"
Text(S.home.itemCount(5)) // "5 items"
🔄 Reusing Modules
One of the main benefits of this modular approach is easy module reuse:
# Copy auth feature to new project with all translations
cp -r old_project/lib/features/auth new_project/lib/features/
# Run generate in new project - translations are ready!
🌐 RTL Support
For full RTL support, use the companion Dart package:
import 'package:modular_l10n/modular_l10n.dart';
// Check if locale is RTL
if (LocaleUtils.isRtl(locale)) {
// Handle RTL layout
}
// Get text direction
TextDirection direction = LocaleUtils.getTextDirection(locale);
// Use extension
bool isRtl = locale.isRtl;
📦 Companion Package
For runtime utilities like LocaleProvider and RTL support, install the modular_l10n Dart package:
dependencies:
modular_l10n: ^1.0.0
📋 Naming Conventions
| Type |
Convention |
Example |
| ARB files |
{moduleName}_{locale}.arb |
auth_en.arb, home_ar.arb |
| Module names |
snake_case |
auth, home, user_profile |
| Key names |
camelCase |
welcomeMessage, loginButton |
🔀 Migration from flutter_intl
If you're migrating from flutter_intl:
- Create
l10n folders in your feature directories
- Split your single
.arb file into module-specific files
- Remove the
flutter_intl configuration from pubspec.yaml
- Run "Modular L10n: Generate Translations"
❓ FAQ
Why use modular localization?
- Scalability: Large apps with many translations become easier to manage
- Team collaboration: Different developers can work on different feature translations
- Reusability: Copy entire features between projects with translations included
- Clean architecture: Keeps related code and translations together
Does it work with existing flutter_intl projects?
Yes! You can gradually migrate by creating l10n folders in your features while keeping the old setup. Once you've moved all translations, remove the old configuration.
Can I use both this and flutter_intl?
We recommend migrating completely to avoid confusion, but they can technically coexist during a transition period.
🐛 Issues & Contributions
Found a bug or have a feature request?
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
Made with ❤️ by Utanium