Agent skill
custom-plugin-flutter-skill-localization
Production-grade Flutter localization mastery - ARB files, flutter_localizations, intl package, pluralization, RTL support, dynamic locale switching with comprehensive code examples
Install this agent skill to your Project
npx add-skill https://github.com/pluginagentmarketplace/custom-plugin-flutter/tree/main/skills/localization
SKILL.md
custom-plugin-flutter: Localization Skill
Quick Start - Production Localization Setup
# pubspec.yaml
dependencies:
flutter_localizations:
sdk: flutter
intl: ^0.19.0
flutter:
generate: true
# l10n.yaml (create in project root)
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
output-class: AppLocalizations
nullable-getter: false
// lib/l10n/app_en.arb
{
"@@locale": "en",
"appTitle": "My App",
"@appTitle": {
"description": "The app title"
},
"welcomeMessage": "Welcome, {name}!",
"@welcomeMessage": {
"description": "Welcome message with user name",
"placeholders": {
"name": {
"type": "String",
"example": "John"
}
}
},
"itemCount": "{count, plural, =0{No items} =1{1 item} other{{count} items}}",
"@itemCount": {
"description": "Number of items",
"placeholders": {
"count": {
"type": "int"
}
}
}
}
// lib/l10n/app_tr.arb
{
"@@locale": "tr",
"appTitle": "Uygulamam",
"welcomeMessage": "Hoş geldin, {name}!",
"itemCount": "{count, plural, =0{Öğe yok} =1{1 öğe} other{{count} öğe}}"
}
// main.dart
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
locale: Locale('en'),
home: HomePage(),
);
}
}
// Usage in widgets
Text(AppLocalizations.of(context).welcomeMessage('John'))
Text(AppLocalizations.of(context).itemCount(5))
1. ARB File Syntax
Basic Messages
{
"@@locale": "en",
"greeting": "Hello",
"@greeting": {
"description": "A simple greeting"
},
"pageTitle": "Settings Page",
"@pageTitle": {
"description": "Title of the settings page",
"context": "SettingsPage"
}
}
Placeholders
{
"welcomeUser": "Welcome, {userName}!",
"@welcomeUser": {
"placeholders": {
"userName": {
"type": "String",
"example": "Alice"
}
}
},
"priceLabel": "Price: {price}",
"@priceLabel": {
"placeholders": {
"price": {
"type": "double",
"format": "currency",
"optionalParameters": {
"symbol": "$",
"decimalDigits": 2
}
}
}
},
"dateLabel": "Date: {date}",
"@dateLabel": {
"placeholders": {
"date": {
"type": "DateTime",
"format": "yMMMd"
}
}
}
}
Pluralization
{
"cartItems": "{count, plural, =0{Your cart is empty} =1{1 item in cart} other{{count} items in cart}}",
"@cartItems": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"remainingAttempts": "{count, plural, =0{No attempts remaining} =1{1 attempt remaining} other{{count} attempts remaining}}",
"@remainingAttempts": {
"placeholders": {
"count": {
"type": "int"
}
}
}
}
Gender Selection
{
"userGreeting": "{gender, select, male{Mr. {name}} female{Ms. {name}} other{{name}}}",
"@userGreeting": {
"placeholders": {
"gender": {
"type": "String"
},
"name": {
"type": "String"
}
}
}
}
2. Date & Number Formatting
import 'package:intl/intl.dart';
// Date formatting
final dateFormatter = DateFormat.yMMMd(locale);
Text(dateFormatter.format(DateTime.now()))
// Number formatting
final numberFormatter = NumberFormat.decimalPattern(locale);
Text(numberFormatter.format(1234567.89))
// Currency formatting
final currencyFormatter = NumberFormat.currency(
locale: locale,
symbol: '\$',
decimalDigits: 2,
);
Text(currencyFormatter.format(99.99))
// Percentage
final percentFormatter = NumberFormat.percentPattern(locale);
Text(percentFormatter.format(0.75)) // 75%
// Compact notation
final compactFormatter = NumberFormat.compact(locale: locale);
Text(compactFormatter.format(1500000)) // 1.5M
3. Dynamic Locale Switching
class LocaleProvider extends ChangeNotifier {
Locale _locale = Locale('en');
Locale get locale => _locale;
void setLocale(Locale locale) {
if (!AppLocalizations.supportedLocales.contains(locale)) return;
_locale = locale;
notifyListeners();
}
Future<void> loadSavedLocale() async {
final prefs = await SharedPreferences.getInstance();
final languageCode = prefs.getString('languageCode');
if (languageCode != null) {
_locale = Locale(languageCode);
notifyListeners();
}
}
Future<void> saveLocale(Locale locale) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('languageCode', locale.languageCode);
setLocale(locale);
}
}
// Usage with Provider
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<LocaleProvider>(
builder: (context, localeProvider, child) {
return MaterialApp(
locale: localeProvider.locale,
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: HomePage(),
);
},
);
}
}
// Language selector
class LanguageSelector extends StatelessWidget {
@override
Widget build(BuildContext context) {
final localeProvider = context.watch<LocaleProvider>();
return DropdownButton<Locale>(
value: localeProvider.locale,
items: AppLocalizations.supportedLocales.map((locale) {
return DropdownMenuItem(
value: locale,
child: Text(_getLanguageName(locale)),
);
}).toList(),
onChanged: (locale) {
if (locale != null) {
localeProvider.saveLocale(locale);
}
},
);
}
String _getLanguageName(Locale locale) {
switch (locale.languageCode) {
case 'en': return 'English';
case 'tr': return 'Türkçe';
case 'es': return 'Español';
default: return locale.languageCode;
}
}
}
4. RTL (Right-to-Left) Support
// Automatic direction based on locale
MaterialApp(
locale: Locale('ar'), // Arabic - RTL
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
)
// Check directionality
final isRtl = Directionality.of(context) == TextDirection.rtl;
// Force direction
Directionality(
textDirection: TextDirection.rtl,
child: MyWidget(),
)
// Directional padding
Padding(
padding: EdgeInsetsDirectional.only(start: 16, end: 8),
child: Text('Directional padding'),
)
// Positioned directionally
PositionedDirectional(
start: 0,
end: null,
child: widget,
)
// Row with automatic alignment
Row(
textDirection: Directionality.of(context),
children: [...],
)
// Icons that should flip
Transform.flip(
flipX: isRtl,
child: Icon(Icons.arrow_forward),
)
5. Testing Localization
void main() {
testWidgets('displays localized text in Turkish', (tester) async {
await tester.pumpWidget(
MaterialApp(
locale: Locale('tr'),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: HomePage(),
),
);
expect(find.text('Hoş geldin!'), findsOneWidget);
});
testWidgets('handles pluralization correctly', (tester) async {
await tester.pumpWidget(
MaterialApp(
locale: Locale('en'),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: Builder(
builder: (context) {
return Column(
children: [
Text(AppLocalizations.of(context).itemCount(0)),
Text(AppLocalizations.of(context).itemCount(1)),
Text(AppLocalizations.of(context).itemCount(5)),
],
);
},
),
),
);
expect(find.text('No items'), findsOneWidget);
expect(find.text('1 item'), findsOneWidget);
expect(find.text('5 items'), findsOneWidget);
});
testWidgets('RTL layout is correct for Arabic', (tester) async {
await tester.pumpWidget(
MaterialApp(
locale: Locale('ar'),
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [Locale('ar')],
home: HomePage(),
),
);
final direction = Directionality.of(tester.element(find.byType(HomePage)));
expect(direction, TextDirection.rtl);
});
}
6. slang Package Alternative
// Alternative: slang package for type-safe translations
// slang.yaml
base_locale: en
input_directory: lib/i18n
output_directory: lib/gen
// lib/i18n/strings_en.i18n.json
{
"greeting": "Hello $name",
"items": {
"zero": "No items",
"one": "One item",
"other": "$n items"
}
}
// Usage
Text(t.greeting(name: 'John'))
Text(t.items(n: 5))
Troubleshooting Guide
Issue: Localization not loading
1. Run: flutter gen-l10n
2. Verify l10n.yaml in project root
3. Check ARB file syntax (valid JSON)
4. Ensure flutter: generate: true in pubspec.yaml
5. Import: flutter_gen/gen_l10n/app_localizations.dart
Issue: Locale not recognized
1. Verify locale is in supportedLocales
2. Check locale code format (en vs en_US)
3. Ensure localizationsDelegates includes your delegate
4. Check @@locale in ARB file matches
Issue: Placeholders not working
1. Verify placeholder name matches exactly
2. Check placeholder type in @message
3. Ensure placeholder syntax: {name}
4. Run flutter gen-l10n to regenerate
Issue: RTL not applying
1. Add GlobalWidgetsLocalizations.delegate
2. Use Directional variants (EdgeInsetsDirectional)
3. Check Directionality widget wrapping
4. Verify locale is RTL language
Localization Best Practices
1. Never hardcode strings in widgets
2. Use descriptive keys (settingsPageTitle vs title)
3. Include context in @descriptions
4. Test all supported locales
5. Handle long text gracefully (overflow)
6. Use ICU message format for complex cases
7. Keep translations organized by feature
8. Review with native speakers
Build globally accessible Flutter apps with proper localization.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
custom-plugin-flutter-skill-animations
Production-grade Flutter animations mastery - Implicit and explicit animations, AnimationController, Hero transitions, physics-based motion, Lottie/Rive integration, 60fps optimization with comprehensive code examples
custom-plugin-flutter-skill-navigation
Production-grade Flutter navigation mastery - Navigator 2.0, GoRouter, deep linking, nested navigation, route guards, web URL handling with comprehensive code examples
custom-plugin-flutter-skill-testing
1600+ lines of testing mastery - unit tests, widget tests, integration tests, E2E, coverage, mocking with production-ready code examples.
custom-plugin-flutter-skill-accessibility
Production-grade Flutter accessibility mastery - Semantics API, screen readers (VoiceOver/TalkBack), WCAG 2.1 AA/AAA compliance, inclusive design patterns, automated a11y testing with comprehensive code examples
custom-plugin-flutter-skill-state
2300+ lines of state management mastery - all patterns (Provider, Riverpod, BLoC, GetX), dependency injection, persistence, testing with production-ready code examples.
custom-plugin-flutter-skill-database
1800+ lines of database architecture mastery - SQLite, Hive, ObjectBox, Firestore, encryption, offline-first, sync with production-ready code examples.
Didn't find tool you were looking for?