Flutter国际化与本地化完全指南
引言
国际化是构建全球化应用的关键环节,Flutter提供了完善的国际化支持。本文将深入探讨Flutter中的国际化和本地化技术。
一、基础配置
1.1 添加依赖
dependencies: flutter_localizations: sdk: flutter intl: ^0.18.11.2 更新main.dart
import 'package:flutter_localizations/flutter_localizations.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: const [ Locale('en', ''), Locale('zh', 'CN'), Locale('ja', ''), ], home: const HomePage(), ); } }二、创建本地化资源
2.1 创建arb文件
lib/l10n/app_en.arb
{ "@@locale": "en", "title": "Hello World", "welcome": "Welcome to our app!", "greeting": "Hello {name}!", "count": "{count, plural, zero{No items} one{One item} other{{count} items}}", "gender": "{gender, select, male{He} female{She} other{They}} likes this." }lib/l10n/app_zh.arb
{ "@@locale": "zh", "title": "你好世界", "welcome": "欢迎来到我们的应用!", "greeting": "你好 {name}!", "count": "{count, plural, zero{没有项目} one{一个项目} other{{count}个项目}}", "gender": "{gender, select, male{他} female{她} other{他们}}喜欢这个。" }lib/l10n/app_ja.arb
{ "@@locale": "ja", "title": "こんにちは世界", "welcome": "アプリへようこそ!", "greeting": "こんにちは {name}!", "count": "{count, plural, zero{アイテムがありません} one{アイテム1つ} other{アイテム{count}個}}", "gender": "{gender, select, male{彼は} female{彼女は} other{彼らは}}これが好きです。" }2.2 配置pubspec.yaml
flutter: generate: true assets: - lib/l10n/2.3 生成代码
flutter pub get三、使用本地化字符串
3.1 基础使用
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { final loc = AppLocalizations.of(context)!; return Scaffold( appBar: AppBar(title: Text(loc.title)), body: Center( child: Column( children: [ Text(loc.welcome), Text(loc.greeting('John')), ], ), ), ); } }3.2 复数处理
Text(loc.count(0)); // No items / 没有项目 / アイテムがありません Text(loc.count(1)); // One item / 一个项目 / アイテム1つ Text(loc.count(5)); // 5 items / 5个项目 / アイテム5個3.3 性别选择
Text(loc.gender('male')); // He likes this. / 他喜欢这个。 / 彼はこれが好きです。 Text(loc.gender('female')); // She likes this. / 她喜欢这个。 / 彼女はこれが好きです。 Text(loc.gender('other')); // They like this. / 他们喜欢这个。 / 彼らはこれが好きです。四、动态切换语言
4.1 创建语言提供器
class LocaleProvider extends ChangeNotifier { Locale _locale = const Locale('en'); Locale get locale => _locale; void setLocale(Locale locale) { _locale = locale; notifyListeners(); } }4.2 使用Provider包装
void main() { runApp( ChangeNotifierProvider( create: (_) => LocaleProvider(), child: const MyApp(), ), ); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { final localeProvider = Provider.of<LocaleProvider>(context); return MaterialApp( locale: localeProvider.locale, localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: const [ Locale('en', ''), Locale('zh', 'CN'), Locale('ja', ''), ], home: const HomePage(), ); } }4.3 创建语言选择器
class LanguageSelector extends StatelessWidget { const LanguageSelector({super.key}); @override Widget build(BuildContext context) { final localeProvider = Provider.of<LocaleProvider>(context); return DropdownButton<Locale>( value: localeProvider.locale, items: const [ DropdownMenuItem(value: Locale('en'), child: Text('English')), DropdownMenuItem(value: Locale('zh', 'CN'), child: Text('中文')), DropdownMenuItem(value: Locale('ja'), child: Text('日本語')), ], onChanged: (locale) { if (locale != null) { localeProvider.setLocale(locale); } }, ); } }五、日期和数字本地化
5.1 日期格式化
import 'package:intl/intl.dart'; void formatDate() { final date = DateTime.now(); // 默认格式 print(DateFormat.yMMMd().format(date)); // 中文格式 print(DateFormat.yMMMd('zh_CN').format(date)); // 日文格式 print(DateFormat.yMMMd('ja').format(date)); // 自定义格式 print(DateFormat('yyyy-MM-dd HH:mm:ss').format(date)); }5.2 数字格式化
void formatNumber() { final number = 1234567.89; // 默认格式 print(NumberFormat().format(number)); // 中文格式 print(NumberFormat.currency(locale: 'zh_CN').format(number)); // 百分比 print(NumberFormat.percentPattern().format(0.75)); }六、RTL支持
6.1 配置RTL
MaterialApp( locale: const Locale('ar'), supportedLocales: const [ Locale('ar'), ], localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ], home: const HomePage(), );6.2 处理RTL布局
class RtlAwareWidget extends StatelessWidget { const RtlAwareWidget({super.key}); @override Widget build(BuildContext context) { final textDirection = Directionality.of(context); return Row( textDirection: textDirection, children: [ const Text('First'), const Text('Second'), ], ); } }七、最佳实践
7.1 提取本地化键
// 不好 Text(AppLocalizations.of(context)!.title); // 好 extension AppLocalizationsExtension on BuildContext { AppLocalizations get loc => AppLocalizations.of(this)!; } // 使用 Text(context.loc.title);7.2 处理缺失翻译
// 在arb文件中添加默认值 { "title": "Hello World", "@title": { "description": "The title of the app", "type": "text", "placeholders": {} } }7.3 测试多语言
void main() { testWidgets('English locale', (tester) async { await tester.pumpWidget( MaterialApp( locale: const Locale('en'), localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ], home: const HomePage(), ), ); expect(find.text('Hello World'), findsOneWidget); }); testWidgets('Chinese locale', (tester) async { await tester.pumpWidget( MaterialApp( locale: const Locale('zh', 'CN'), localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ], home: const HomePage(), ), ); expect(find.text('你好世界'), findsOneWidget); }); }总结
国际化是构建全球化应用的重要环节,通过合理使用Flutter的国际化支持,你可以:
- 支持多种语言:轻松添加新语言支持
- 格式化日期和数字:根据区域设置自动格式化
- 支持RTL语言:正确处理阿拉伯语、希伯来语等
- 动态切换语言:提供良好的用户体验
掌握国际化技术,让你的应用走向全球!