Localization Setup
The app uses Flutter's built-in flutter_localizations with ARB (Application Resource Bundle) files.
Supported locales (P0): English (en), Hindi (hi)
File Structure
code
lib/ ├── l10n/ │ ├── app_en.arb # English strings (source of truth) │ ├── app_hi.arb # Hindi translations │ └── l10n.yaml # Generation config ├── core/ │ └── l10n/ │ └── generated/ # Auto-generated (do not edit) │ ├── app_localizations.dart │ ├── app_localizations_en.dart │ └── app_localizations_hi.dart
ARB File Format
English (source of truth)
json
{
"@@locale": "en",
"appTitle": "One By Two",
"@appTitle": {
"description": "App name shown in app bar"
},
"youOwe": "You owe {name}",
"@youOwe": {
"description": "Balance text when current user owes money",
"placeholders": {
"name": { "type": "String", "example": "Rahul" }
}
},
"amountInRupees": "₹{amount}",
"@amountInRupees": {
"placeholders": {
"amount": { "type": "String", "example": "150.50" }
}
},
"expenseCount": "{count, plural, =0{No expenses} =1{1 expense} other{{count} expenses}}",
"@expenseCount": {
"description": "Number of expenses in a group",
"placeholders": {
"count": { "type": "int" }
}
},
"memberCount": "{count, plural, =1{1 member} other{{count} members}}",
"@memberCount": {
"placeholders": {
"count": { "type": "int" }
}
}
}
Hindi
json
{
"@@locale": "hi",
"appTitle": "वन बाय टू",
"youOwe": "आप {name} को देते हैं",
"amountInRupees": "₹{amount}",
"expenseCount": "{count, plural, =0{कोई खर्च नहीं} =1{1 खर्च} other{{count} खर्चे}}",
"memberCount": "{count, plural, =1{1 सदस्य} other{{count} सदस्य}}"
}
Usage in Code
dart
// Access localized strings
final l10n = AppLocalizations.of(context)!;
Text(l10n.appTitle);
Text(l10n.youOwe('Rahul'));
Text(l10n.expenseCount(5));
Text(l10n.amountInRupees('150.50'));
Adding New Strings
- •Add to
app_en.arb(English is always the source of truth) - •Add metadata with
@keyfor description and placeholders - •Add to
app_hi.arbwith Hindi translation - •Run code generation:
bash
flutter gen-l10n
- •Use in code via
AppLocalizations.of(context)!.newKey
Rules
- •Never hardcode user-facing strings — always use ARB files
- •English ARB is the source — Hindi follows; missing Hindi keys fall back to English
- •Use ICU message format for plurals, selects, and gender
- •Placeholders must be typed (
String,int,double,DateTime) - •Amount formatting: Always format with
₹symbol and 2 decimal places - •Date formatting: Use
DateFormatfromintlpackage, locale-aware - •Number formatting: Use
NumberFormatfromintlpackage for comma separators (Indian: 1,00,000) - •Do NOT translate:
- •App name in marketing contexts ("One By Two")
- •Currency symbol (₹)
- •Technical identifiers
Indian Number Formatting
India uses a unique grouping: 1,00,000 (not 100,000).
dart
import 'package:intl/intl.dart';
String formatIndianAmount(int paise) {
final rupees = paise / 100;
final formatter = NumberFormat.currency(
locale: 'en_IN',
symbol: '₹',
decimalDigits: 2,
);
return formatter.format(rupees);
}
// 1000000 paise → "₹10,000.00"
// 10000050 paise → "₹1,00,000.50"
l10n.yaml Configuration
yaml
arb-dir: lib/l10n template-arb-file: app_en.arb output-localization-file: app_localizations.dart output-dir: lib/core/l10n/generated synthetic-package: false nullable-getter: false
Testing Localized Strings
dart
testWidgets('displays Hindi text when locale is hi', (tester) async {
await tester.pumpWidget(
MaterialApp(
locale: const Locale('hi'),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: const HomeScreen(),
),
);
expect(find.text('वन बाय टू'), findsOneWidget);
});
Reference
- •Requirements:
docs/REQUIREMENTS.md(Section 7 — English + Hindi P0) - •Architecture:
docs/architecture/01_ARCHITECTURE_OVERVIEW.md(i18n section)