内置组件本地化
-
添加依赖
Flutter默认组件的本地化只需要添加
1flutter_localizations: 2 sdk: flutter使用命令行添加就是
1flutter pub add flutter_localizations --sdk=flutter -
修改入口组件 main.dart
1import 'package:flutter_localizations/flutter_localizations.dart';1return const MaterialApp( 2 title: 'Localizations Sample App', 3 localizationsDelegates: [ 4 GlobalMaterialLocalizations.delegate, 5 GlobalWidgetsLocalizations.delegate, 6 GlobalCupertinoLocalizations.delegate, 7 ], 8 supportedLocales: [ 9 Locale('en'), // English 10 Locale('zh'), // Chinese 11 ], 12 home: MyHomePage(), 13);这样Flutter内置组件所显示的语言就能和系统语言保持一致,如果想要手动修改,只需要添加参数
1return const MaterialApp( 2 ... 3 locale: Locale("zh"), 4);如果想要修改指定的组件,需要使用到
Localizations.override1Widget build(BuildContext context) { 2 return Scaffold( 3 appBar: AppBar( 4 title: Text(widget.title), 5 ), 6 body: Center( 7 child: Column( 8 mainAxisAlignment: MainAxisAlignment.center, 9 children: <Widget>[ 10 Localizations.override( 11 context: context, 12 locale: const Locale('zh'), 13 child: Builder( 14 builder: (context) { 15 return CalendarDatePicker( 16 initialDate: DateTime.now(), 17 firstDate: DateTime(1900), 18 lastDate: DateTime(2100), 19 onDateChanged: (value) {}, 20 ); 21 }, 22 ), 23 ), 24 ], 25 ), 26 ), 27 ); 28}
自定义本地化
根据官方文档,可以利用 flutter_localozations 和 intl 来实现。但是如果根据官方文档,那可不是一般的麻烦,而是相当麻烦,操作步骤包括但不限于
-
修改
pubsepc.yaml -
添加
l10n.yaml -
添加
.arb文件
当然,这一切也不能说是很麻烦,毕竟只要第一次改好,后续只用修改 .arb 文件就能自动运行,但根据这个流程生成的多语言本地化,我觉得有几个问题:
-
自动生成的
.dart文件是保存在{项目目录}/.dart_tool/flutter_gen/gen_l10n目录下的,这会导致项目默认的代码没有多语言相关,只有一些不知所谓的.arb文件,毕竟与多语言相关的代码都是自动生成的 -
也是最重要的一点, 我为什么要在默认语言下重复定义一个不能带空格,只允许定义符合 dart方法名称 的关键字以供调用,比如一个简单的字符串
1Text("Hello World")我必须在默认语言定义一个
1// app_es.arb 2"helloWorld": "Hello World"然后在其它语言定义
1// app_zh.arb 2"helloWorld": "你好 世界"最后再修改默认的调用
1Text(AppLocations.of(context).helloWorld)我为什么不能直接使用原有的字符串呢,这样就不用再为默认的语言添加额外的翻译,比如
1Text(AppLocations.of(context).tr("Hello World"))
所以,我仔细研究了一下,大抵不用如此麻烦
自定义本地化(非代码自动生成)
-
首先添加 l10n.dart
1import 'dart:async'; 2 3import 'package:flutter/foundation.dart'; 4import 'package:flutter/widgets.dart'; 5import 'package:flutter_localizations/flutter_localizations.dart'; 6import 'package:intl/intl.dart' as intl; 7 8import 'l10n_en.dart'; 9import 'l10n_zh.dart'; 10 11abstract class L10n { 12 L10n(String locale) 13 : localeName = intl.Intl.canonicalizedLocale(locale.toString()); 14 15 final String localeName; 16 17 static L10n? of(BuildContext context) { 18 return Localizations.of<L10n>(context, L10n); 19 } 20 21 static const LocalizationsDelegate<L10n> delegate = _L10nDelegate(); 22 23 static const List<LocalizationsDelegate<dynamic>> localizationsDelegates = 24 <LocalizationsDelegate<dynamic>>[ 25 delegate, 26 GlobalMaterialLocalizations.delegate, 27 GlobalCupertinoLocalizations.delegate, 28 GlobalWidgetsLocalizations.delegate, 29 ]; 30 31 static const List<Locale> supportedLocales = <Locale>[ 32 Locale('en'), 33 Locale('zh') 34 ]; 35 36 String tr(String key); 37} 38 39class _L10nDelegate extends LocalizationsDelegate<L10n> { 40 const _L10nDelegate(); 41 42 @override 43 Future<L10n> load(Locale locale) { 44 return SynchronousFuture<L10n>(lookupL10n(locale)); 45 } 46 47 @override 48 bool isSupported(Locale locale) => 49 <String>['en', 'zh'].contains(locale.languageCode); 50 51 @override 52 bool shouldReload(_L10nDelegate old) => false; 53} 54 55L10n lookupL10n(Locale locale) { 56 // Lookup logic when only language code is specified. 57 switch (locale.languageCode) { 58 case 'en': 59 return L10nEn(); 60 case 'zh': 61 return L10nZh(); 62 } 63 64 throw FlutterError( 65 'L10n.delegate failed to load unsupported locale "$locale". This is likely ' 66 'an issue with the localizations generation tool. Please file an issue ' 67 'on GitHub with a reproducible sample app and the gen-l10n configuration ' 68 'that was used.'); 69}上述代码其实是由根据官方文档自动生成的
.dart文件转化而来 -
添加默认语言的翻译
1// l10n_en.dart 2import 'l10n.dart'; 3 4class L10nEn extends L10n { 5 L10nEn([String locale = 'en']) : super(locale); 6 7 @override 8 String tr(String key) { 9 return translations[key] ?? key; 10 } 11} 12 13const translations = {};对的,你没有看错,
translations甚至可以是空的,这样就不用重复定义默认语言的翻译 -
添加其它语言的翻译
1// l10n_zh.dart 2import 'l10n.dart'; 3 4class L10nZh extends L10n { 5 L10nZh([String locale = 'zh']) : super(locale); 6 7 @override 8 String tr(String key) { 9 return translations[key] ?? key; 10 } 11} 12 13const translations = { 14 "Settings": "设置", 15 "Basic Settings": "基础设置", 16 "Theme": "主题", 17 "Language": "语言", 18 "About": "关于", 19 "Help": "帮助", 20}; -
修改 main.dart 入口组件
1import 'app/l10n/l10n.dart'; 2 3return const MaterialApp( 4 title: 'Localizations Sample App', 5 localizationsDelegates: L10n.localizationsDelegates, 6 supportedLocales: L10n.supportedLocales, 7 home: MyHomePage(), 8);这样就能使用自定义的翻译了
本地化多语言的使用
最常用的是在 Text 组件里
1Text(L10n.of(context)!.tr("Hello World"))
但是所有的字符都要添加 L10n.of(context)! 未免有些麻烦,所以我增加了自定义扩展
-
BuildContext1extension L10nContext on BuildContext { 2 String tr(String key) { 3 final t = L10n.of(this); 4 if (t == null) { 5 return key; 6 } 7 return t.tr(key); 8 } 9}使用方式
1Text(context.tr("Hello World")) -
String1extension L10nString on String { 2 String tr(BuildContext context) { 3 final t = L10n.of(context); 4 if (t == null) { 5 return this; 6 } 7 return t.tr(this); 8 } 9}使用方式
1Text("Hello World".tr(context)) -
Text1extension L10nText on Text { 2 Text tr(BuildContext context) { 3 final t = L10n.of(context); 4 if (t == null || data == null) { 5 return this; 6 } 7 return Text(t.tr(data ?? ''), 8 key: key, 9 style: style, 10 strutStyle: strutStyle, 11 textAlign: textAlign, 12 textDirection: textDirection, 13 locale: locale, 14 softWrap: softWrap, 15 overflow: overflow, 16 textScaler: textScaler, 17 maxLines: maxLines, 18 semanticsLabel: semanticsLabel, 19 textWidthBasis: textWidthBasis); 20 } 21}使用方式
1Text("Hello World").tr(context)如此,就能最大限度的较少对原有代码的侵略性修改
优化多语言选择
我这里选用的是 riverpod 进行状态管理,首先定义一个本地语言的状态
1final localeProvider = StateProvider<String>((ref) {
2 return "zh";
3});
接着修改 main.dart
1class MyApp extends ConsumerWidget {
2 const MyApp({super.key});
3
4 @override
5 Widget build(BuildContext context, WidgetRef ref) {
6 final localeCode = ref.watch(localeProvider);
7
8 return MaterialApp(
9 locale: L10n.delegate.isSupported(localeCode) ? Locale(localeCode) : null,
10 ...
11 );
12 }
13}
这样就能很方便地修改应用的显示语言
1ref.read(localeProvider.notifier).state = "zh";
知识共享署名-非商业性使用-相同方式共享4.0国际许可协议