Flutter 国际化与本地化完全指南
·
Flutter 国际化与本地化完全指南
引言
国际化(Internationalization)和本地化(Localization)是构建全球化应用的关键。Flutter 提供了强大的国际化支持,让应用能够轻松支持多种语言和地区。本文将深入探讨 Flutter 国际化的各种技巧和最佳实践。
基础配置
添加依赖
dependencies:
flutter_localizations:
sdk: flutter
intl: ^0.18.0
配置 MaterialApp
import 'package:flutter_localizations/flutter_localizations.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Internationalization',
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('en', 'US'),
const Locale('zh', 'CN'),
const Locale('ja', 'JP'),
],
home: HomePage(),
);
}
}
高级技巧一:创建本地化资源
使用 intl 包
// l10n/messages_all.dart
import 'dart:async';
import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';
final MessageLookup messages = MessageLookup();
class MessageLookup extends MessageLookupByLibrary {
@override
String? lookupMessage(
String? messageText,
String? locale,
String? name,
List<Object>? args,
String? meaning,
Map<String, String>? examples,
) {
return messageText;
}
}
创建本地化文件
// l10n/intl_en.arb
{
"helloWorld": "Hello World!",
"welcome": "Welcome to Flutter",
"greeting": "Hello {name}!",
"count": "{count, plural, zero{No items} one{1 item} other{{count} items}}"
}
// l10n/intl_zh.arb
{
"helloWorld": "你好世界!",
"welcome": "欢迎来到 Flutter",
"greeting": "你好 {name}!",
"count": "{count, plural, zero{没有项目} one{1个项目} other{{count}个项目}}"
}
高级技巧二:使用 flutter_localizations
创建自定义 LocalizationsDelegate
class AppLocalizations {
final Locale locale;
AppLocalizations(this.locale);
static AppLocalizations? of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();
Map<String, String> _localizedStrings = {};
Future<void> load() async {
String jsonString = await rootBundle.loadString(
'i18n/${locale.languageCode}.json',
);
Map<String, dynamic> jsonMap = json.decode(jsonString);
_localizedStrings = jsonMap.map((key, value) => MapEntry(key, value.toString()));
}
String translate(String key) {
return _localizedStrings[key] ?? key;
}
}
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
@override
bool isSupported(Locale locale) {
return ['en', 'zh', 'ja'].contains(locale.languageCode);
}
@override
Future<AppLocalizations> load(Locale locale) async {
AppLocalizations localizations = AppLocalizations(locale);
await localizations.load();
return localizations;
}
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
配置 MaterialApp
MaterialApp(
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
const Locale('en', 'US'),
const Locale('zh', 'CN'),
const Locale('ja', 'JP'),
],
)
高级技巧三:动态切换语言
创建语言切换服务
class LanguageService extends ChangeNotifier {
Locale _currentLocale = const Locale('en', 'US');
Locale get currentLocale => _currentLocale;
void setLocale(Locale locale) {
_currentLocale = locale;
notifyListeners();
}
}
使用 GetX 切换语言
// 在 GetX 中配置
GetMaterialApp(
locale: Get.deviceLocale,
fallbackLocale: const Locale('en', 'US'),
translations: MyTranslations(),
)
// 切换语言
Get.updateLocale(const Locale('zh', 'CN'));
高级技巧四:格式化日期和数字
日期格式化
// 使用 intl 包
final date = DateTime.now();
final formatter = DateFormat('yyyy-MM-dd HH:mm:ss', 'zh_CN');
print(formatter.format(date)); // 2024-01-15 14:30:00
数字格式化
final number = 1234567.89;
final formatter = NumberFormat('#,##0.00', 'zh_CN');
print(formatter.format(number)); // 1,234,567.89
货币格式化
final amount = 1234.56;
final formatter = NumberFormat.currency(
locale: 'zh_CN',
symbol: '¥',
);
print(formatter.format(amount)); // ¥1,234.56
高级技巧五:RTL 支持
配置 RTL
MaterialApp(
locale: const Locale('ar'),
supportedLocales: [
const Locale('ar'),
],
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
)
检测文本方向
final direction = Directionality.of(context);
if (direction == TextDirection.rtl) {
// RTL 布局
} else {
// LTR 布局
}
实战案例:多语言应用
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context);
return Scaffold(
appBar: AppBar(
title: Text(localizations?.translate('welcome') ?? 'Welcome'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(localizations?.translate('helloWorld') ?? 'Hello World'),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// 切换语言
final locale = Localizations.localeOf(context);
if (locale.languageCode == 'en') {
Get.updateLocale(const Locale('zh', 'CN'));
} else {
Get.updateLocale(const Locale('en', 'US'));
}
},
child: Text(localizations?.translate('changeLanguage') ?? 'Change Language'),
),
],
),
),
);
}
}
实战案例:动态语言切换
class LanguageSelector extends StatelessWidget {
final List<Map<String, String>> languages = [
{'code': 'en', 'name': 'English'},
{'code': 'zh', 'name': '中文'},
{'code': 'ja', 'name': '日本語'},
];
@override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: Get.locale?.languageCode,
items: languages.map((lang) {
return DropdownMenuItem(
value: lang['code'],
child: Text(lang['name']!),
);
}).toList(),
onChanged: (value) {
if (value != null) {
Get.updateLocale(Locale(value));
}
},
);
}
}
常见问题与解决方案
Q1:如何支持地区变体?
A:使用完整的 locale 代码:
supportedLocales: [
const Locale('en', 'US'),
const Locale('en', 'GB'),
const Locale('zh', 'CN'),
const Locale('zh', 'TW'),
],
Q2:如何处理复数形式?
A:使用 ICU 消息格式:
{
"items": "{count, plural, zero{No items} one{1 item} other{{count} items}}"
}
Q3:如何获取设备语言?
A:使用 WidgetsBinding.instance.window.locale:
final deviceLocale = WidgetsBinding.instance.window.locale;
最佳实践
1. 集中管理翻译资源
// 错误:硬编码字符串
Text('Hello World')
// 正确:使用本地化
Text(AppLocalizations.of(context)?.translate('helloWorld') ?? 'Hello World')
2. 使用 ARB 文件
{
"helloWorld": "Hello World!",
"@helloWorld": {
"description": "The classic hello world message"
}
}
3. 支持 RTL 语言
Directionality(
textDirection: TextDirection.rtl,
child: Text('مرحبا بالعالم'),
)
总结
国际化是构建全球化应用的重要环节。通过本文的学习,你应该能够:
- 配置基本的国际化支持
- 创建多语言资源文件
- 实现动态语言切换
- 格式化日期、数字和货币
- 支持 RTL 语言
掌握这些技巧,能够帮助你构建更加友好的全球化应用。
更多推荐

所有评论(0)