Skip to content

Localization

DWallet features multi-language support built using slang - a type-safe i18n solution for Flutter.

The app currently supports multiple languages with the infrastructure to easily add more.

DWallet uses the slang package for type-safe translations:

  1. Define translations in JSON/YAML files
  2. Run code generation
  3. Use generated classes for type-safe access
lib/
├── i18n/ # Translation files
│ ├── strings.i18n.json # Base language (English)
│ ├── strings_es.i18n.json # Spanish
│ └── strings_fr.i18n.json # French
└── main.dart

Create a new file in lib/i18n/:

lib/i18n/strings_ja.i18n.json
{
"appName": "DWallet",
"welcome": "ようこそ",
"settings": {
"title": "設定",
"appearance": "外観",
"language": "言語"
},
"wallet": {
"title": "ウォレット",
"balance": "残高",
"addNew": "新規追加"
}
}
Terminal window
flutter pub run slang

This generates type-safe translation classes.

In main.dart, ensure the locale is supported:

ShadApp.router(
localizationsDelegates: const [
...AppLocaleUtils.localizationsDelegates,
],
supportedLocales: AppLocaleUtils.supportedLocales,
// ...
)
import '../../i18n/strings.g.dart';
class HomeView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final t = Translations.of(context);
return Scaffold(
appBar: AppBar(
title: Text(t.wallet.title),
),
body: Text(t.welcome),
);
}
}
final localeProvider = StateProvider<AppLocale>((ref) {
return AppLocale.en; // Default
});
// Change locale
ref.read(localeProvider.notifier).state = AppLocale.ja;

Organize translations hierarchically:

{
"common": {
"save": "Save",
"cancel": "Cancel",
"delete": "Delete",
"confirm": "Are you sure?"
},
"home": {
"title": "Home",
"totalBalance": "Total Balance",
"income": "Income",
"expense": "Expense"
},
"transaction": {
"add": "Add Transaction",
"income": "Income",
"expense": "Expense",
"category": "Category",
"amount": "Amount",
"note": "Note"
},
"wallet": {
"title": "Wallets",
"add": "Add Wallet",
"types": {
"cash": "Cash",
"bank": "Bank",
"mobileMoney": "Mobile Money",
"other": "Other"
}
},
"settings": {
"title": "Settings",
"appearance": "Appearance",
"security": "Security",
"language": "Language"
}
}

Slang supports pluralization:

{
"transactionCount": {
"zero": "No transactions",
"one": "One transaction",
"other": "$count transactions"
}
}
t.transactionCount(count: 5); // "5 transactions"

Use intl package alongside slang:

import 'package:intl/intl.dart';
final dateFormat = DateFormat.yMMMd().format(transaction.date);
final currencyFormat = NumberFormat.currency(
symbol: currency.symbol,
).format(amount);
  1. Use semantic keys: saveButton not button1
  2. Group by feature: home.title, wallet.add
  3. Keep base language complete: Always translate all keys
  4. Use placeholders: "Hello {name}" not string concatenation
  5. Context-aware: Provide context for translators in comments

In main.dart:

void main() {
WidgetsFlutterBinding.ensureInitialized();
// Set default locale
LocaleSettings.useDeviceLocale();
runApp(ProviderScope(child: DWalletApp()));
}