DEV Community

kanta13jp1
kanta13jp1

Posted on

Flutter Localization Complete Guide — Building Multi-Language Apps with i18n

Flutter Localization Complete Guide — Building Multi-Language Apps with i18n

Going global with your Flutter app requires proper localization. In this guide, we'll implement Japanese/English language switching using Flutter's official flutter_localizations package and intl.

Why Localization Matters

For indie developers targeting the global market, supporting at least Japanese and English is essential. Flutter has built-in support for Locale and LocalizationsDelegate, making multi-language support achievable with minimal code.

Setup

# pubspec.yaml
dependencies:
  flutter_localizations:
    sdk: flutter
  intl: ^0.19.0

flutter:
  generate: true
Enter fullscreen mode Exit fullscreen mode
# l10n.yaml
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
Enter fullscreen mode Exit fullscreen mode

Managing Strings with ARB Files

// lib/l10n/app_en.arb
{
  "@@locale": "en",
  "appTitle": "My App",
  "@appTitle": { "description": "Application title" },
  "greeting": "Hello, {name}!",
  "@greeting": {
    "placeholders": {
      "name": { "type": "String" }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
// lib/l10n/app_ja.arb
{
  "@@locale": "ja",
  "appTitle": "マイアプリ",
  "greeting": "こんにちは、{name}さん!"
}
Enter fullscreen mode Exit fullscreen mode

Integrating with MaterialApp

import 'package:flutter_gen/gen_l10n/app_localizations.dart';

MaterialApp(
  localizationsDelegates: AppLocalizations.localizationsDelegates,
  supportedLocales: AppLocalizations.supportedLocales,
  home: const HomePage(),
)
Enter fullscreen mode Exit fullscreen mode

Using Translated Strings

// In any Widget
Text(AppLocalizations.of(context)!.greeting('kanta'))
Enter fullscreen mode Exit fullscreen mode

Localizing Numbers and Dates

import 'package:intl/intl.dart';

final formatter = NumberFormat.currency(locale: 'ja_JP', symbol: '¥');
print(formatter.format(1980)); // ¥1,980

final dateFormatter = DateFormat.yMMMd('en');
print(dateFormatter.format(DateTime.now())); // Dec 23, 2028
Enter fullscreen mode Exit fullscreen mode

Dynamic Language Switching

Manage Locale with Riverpod to allow switching from a settings screen:

final localeProvider = StateProvider<Locale>((ref) => const Locale('en'));

// MaterialApp
MaterialApp(
  locale: ref.watch(localeProvider),
  ...
)

// Settings screen
ElevatedButton(
  onPressed: () => ref.read(localeProvider.notifier).state = const Locale('ja'),
  child: const Text('日本語に切り替え'),
)
Enter fullscreen mode Exit fullscreen mode

Persisting with Supabase

Save the user's language preference in Supabase for cross-device sync:

// Save language preference
await supabase.from('user_settings')
  .upsert({'user_id': userId, 'locale': 'en'});

// Load on startup
final data = await supabase.from('user_settings')
  .select('locale')
  .eq('user_id', userId)
  .single();
ref.read(localeProvider.notifier).state = Locale(data['locale']);
Enter fullscreen mode Exit fullscreen mode

Summary

Flutter's i18n system uses ARB files with flutter gen-l10n for type-safe string management. Combined with Riverpod, dynamic locale switching is straightforward. If you're planning to go global, implement localization early in your project.


Building an AI Life Management app with Flutter × Supabase at 自分株式会社. Sharing indie dev insights every week.

Top comments (0)