Flutter国际化插件i18next的使用
Flutter国际化插件i18next的使用
简介
i18next
是一个为Dart适配的标准i18next库,支持Flutter的本地化技术。此包仍在开发中,可能会频繁发生破坏性变化。
特性
- 支持变量、命名空间、上下文
- 支持简单和多重复数形式
- 支持复数和上下文回退
- 支持Locale和命名空间回退
- 获取字符串或对象树
- 支持嵌套
- 支持Flutter的
LocalizationsDelegate
- 从
pubspec.yaml
获取资产包本地化数据源
不支持特性
- Sprintf支持
- 资源缓存
- 从服务器获取资源文件
- 自定义后处理
使用方法
添加依赖
在pubspec.yaml
文件中添加以下依赖:
dependencies:
i18next: ^0.5.0
初始化I18NextLocalizationDelegate
在应用中创建并注册I18NextLocalizationDelegate
:
I18NextLocalizationDelegate(
locales: widget.locales,
dataSource: AssetBundleLocalizationDataSource(bundlePath: 'localizations'),
options: I18NextOptions(...),
),
访问与使用
通过Localizations.of
访问i18next
实例:
Widget build(BuildContext context) {
I18Next.of(context).t('key');
...
}
或者直接实例化I18Next
:
I18Next(
locale,
resourceStore: ...,
options: I18NextOptions(...)
);
示例代码
以下是一个完整的示例应用程序,展示了如何使用i18next
进行国际化:
main.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:i18next/i18next.dart';
import 'package:intl/intl.dart';
import 'localizations.dart';
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
final List<Locale> locales = const [
Locale('en', 'US'),
Locale('pt', 'BR'),
];
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Locale locale;
@override
void initState() {
super.initState();
locale = widget.locales.first;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'I18next Demo',
theme: ThemeData(
dividerTheme: const DividerThemeData(
color: Colors.black45,
space: 32.0,
),
),
localizationsDelegates: [
...GlobalMaterialLocalizations.delegates,
I18NextLocalizationDelegate(
locales: widget.locales,
dataSource: AssetBundleLocalizationDataSource(bundlePath: 'localizations'),
options: I18NextOptions(formats: formatters()),
),
],
home: MyHomePage(
supportedLocales: widget.locales,
onUpdateLocale: updateLocale,
),
locale: locale,
supportedLocales: widget.locales,
);
}
void updateLocale(Locale newLocale) {
setState(() {
locale = newLocale;
});
}
static Map<String, ValueFormatter> formatters() => {
'uppercase': (value, format, locale, options) => value?.toString().toUpperCase(),
'lowercase': (value, format, locale, options) => value?.toString().toLowerCase(),
'datetime': (value, format, locale, options) {
if (value is! DateTime) return value;
var dateFormat = format.options['format'];
dateFormat = dateFormat is String ? dateFormat : 'dd/MM/yyyy';
return DateFormat(dateFormat, locale.toString()).format(value);
},
};
}
class MyHomePage extends StatefulWidget {
const MyHomePage({
Key? key,
required this.supportedLocales,
required this.onUpdateLocale,
}) : super(key: key);
final List<Locale> supportedLocales;
final ValueChanged<Locale> onUpdateLocale;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
String _gender = '';
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final homepageL10n = HomePageL10n.of(context);
final counterL10n = CounterL10n.of(context);
return Scaffold(
appBar: AppBar(title: Text(homepageL10n.title)),
body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
CupertinoSegmentedControl<Locale>(
children: {
for (final e in widget.supportedLocales) e: Text(e.toString())
},
groupValue: Localizations.localeOf(context),
onValueChanged: widget.onUpdateLocale,
),
const Divider(),
Text(
homepageL10n.hello(name: 'Name', world: 'Flutter'),
style: theme.textTheme.titleLarge,
),
Text(
homepageL10n.today(DateTime.now()),
style: theme.textTheme.titleSmall,
),
CupertinoSegmentedControl<String>(
padding: const EdgeInsets.symmetric(vertical: 8),
children: const {
'male': Text('MALE'),
'female': Text('FEMALE'),
'': Text('OTHER'),
},
groupValue: _gender,
onValueChanged: updateGender,
),
Text(homepageL10n.gendered(_gender)),
const Divider(),
Text(
counterL10n.clicked(_counter),
style: theme.textTheme.headlineMedium,
),
TextButton(
onPressed: resetCounter,
child: Text(counterL10n.resetCounter),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: incrementCounter,
tooltip: counterL10n.clickMe,
child: const Icon(Icons.add),
),
);
}
void incrementCounter() => setState(() => _counter++);
void resetCounter() => setState(() => _counter = 0);
void updateGender(String gender) => setState(() => _gender = gender);
}
localizations.dart
import 'package:flutter/material.dart';
import 'package:i18next/i18next.dart';
class HomePageL10n {
static HomePageL10n of(BuildContext context) {
return HomePageL10n(I18Next.of(context));
}
final I18Next i18next;
HomePageL10n(this.i18next);
String get title => i18next.t('home:title');
String hello({required String name, required String world}) =>
i18next.t('home:hello', arguments: {'name': name, 'world': world});
String today(DateTime date) =>
i18next.t('home:today', arguments: {'now': date});
String gendered(String gender) =>
i18next.t('home:gendered', context: gender);
}
class CounterL10n {
static CounterL10n of(BuildContext context) {
return CounterL10n(I18Next.of(context));
}
final I18Next i18next;
CounterL10n(this.i18next);
String clicked(int count) =>
i18next.t('counter:clicked', count: count);
String get resetCounter => i18next.t('counter:resetCounter');
String get clickMe => i18next.t('counter:clickMe');
}
localizations/en_US.json
{
"home": {
"title": "Home Page",
"hello": "Hello {{name}} from {{world}}!",
"today": "Today is {{now, datetime(format:dd/MM/yyyy)}}",
"gendered": "{{context, male:A boyfriend, female:A girlfriend, A friend}}"
},
"counter": {
"clicked": "{{count}} clicks",
"resetCounter": "Reset Counter",
"clickMe": "Click Me"
}
}
localizations/pt_BR.json
{
"home": {
"title": "Página Inicial",
"hello": "Olá {{name}} do {{world}}!",
"today": "Hoje é {{now, datetime(format:dd/MM/yyyy)}}",
"gendered": "{{context, male:Um namorado, female:Uma namorada, Um amigo}}"
},
"counter": {
"clicked": "{{count}} cliques",
"resetCounter": "Redefinir Contador",
"clickMe": "Clique Aqui"
}
}
以上代码展示了如何在Flutter项目中使用i18next
进行国际化。你可以根据需要扩展和修改这些代码以适应你的具体需求。
更多关于Flutter国际化插件i18next的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter国际化插件i18next的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter中,虽然i18next
这个库本身并不是专门为Flutter设计的(i18next
更常见于JavaScript/React生态),但Flutter有一个非常强大且广泛使用的国际化插件——flutter_localizations
。不过,如果你确实想使用类似i18next
功能的插件,你可以考虑一些第三方库,比如flutter_i18n
,它提供了类似的功能。但请注意,下面我将重点展示如何使用Flutter内置的国际化支持。
以下是一个使用flutter_localizations
和Intl
包进行国际化的简单示例:
-
添加依赖: 在你的
pubspec.yaml
文件中添加intl
依赖:dependencies: flutter: sdk: flutter intl: ^0.17.0 # 请检查最新版本
-
创建翻译文件: 为不同的语言创建ARB(Application Resource Bundle)文件。例如,
messages_en.arb
和messages_zh.arb
。messages_en.arb
:{ "welcome_message": "Welcome to Flutter!" }
messages_zh.arb
:{ "welcome_message": "欢迎来到Flutter!" }
-
生成Dart类: 使用
flutter pub run intl_translation:extract_to_arb
命令提取字符串,然后使用flutter pub run intl_translation:generate_from_arb
生成Dart类。这将生成一个包含所有翻译的文件,比如l10n/messages_all.dart
。 -
设置MaterialApp: 在你的
MaterialApp
中配置本地化支持。import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', supportedLocales: [ Locale('en', ''), // 英语 Locale('zh', ''), // 中文 ], localizationsDelegates: [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ], locale: Locale('en'), // 默认语言 home: MyHomePage(), ); } } class MyHomePage extends StatelessWidget { @override Widget build(BuildContext context) { final AppLocalizations localizations = AppLocalizations.of(context)!; return Scaffold( appBar: AppBar( title: Text(localizations.welcomeMessage), ), body: Center( child: Text(localizations.welcomeMessage), ), ); } }
-
使用翻译: 在你的UI组件中,通过
AppLocalizations.of(context)!.yourKey
访问翻译文本。
这个示例展示了如何使用Flutter内置的国际化支持来创建多语言应用。如果你确实想使用类似i18next
的第三方库,你可能需要搜索Flutter社区中是否有类似的实现,并遵循该库的文档进行设置和使用。不过,对于大多数Flutter应用来说,内置的flutter_localizations
和Intl
包已经足够强大和灵活。