最近发布的Flutter 3,以其美妙的开发体验和在许多平台上运行的单一代码库的承诺,已经成为许多iOS和Android应用程序的瑞士军刀,同时桌面和Web应用程序也慢慢加快了步伐。
当你发布一个将在全球范围内使用的应用程序时,只用一种语言并不能为每个最终用户提供相同的体验。虽然英语是使用最广泛的语言之一,但翻译应用程序使其更容易被所有用户接受和理解。出于这个原因,我们将在本文中学习Flutter应用程序的本地化。
我们将建立什么?
我们将尝试通过使用一个每当你创建Flutter项目时都会派上用场的反例应用程序来理解本地化,并在反例中做一些改变来演示本地化。
我们将使用Flutter本地化包成功地将我们的应用程序翻译成另一种语言,包括单词和短语的插值以及单数和复数的正确翻译。
内容表
项目配置
-
将所需的依赖性添加到
pubspec.yaml:environment: sdk: ">=2.16.1 <3.0.0" dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter intl: ^0.17.0 cupertino_icons: ^1.0.2 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^1.0.0 flutter: generate: true uses-material-design: true
如上所述,修改你的pubspec.yaml 文件。flutter localizations 包括一个本地的本地化包和intl ,可以实现国际化和本地化,包括消息翻译、复数和性别。generate: true 行对于本地化包的自动代码生成至关重要,可以节省大量的时间。
创建一个l10n.yaml 文件到我们项目的根部;即lib/l10n.yaml 。这个文件指定了我们的翻译文件的位置,以及自动生成的Dart文件的名称。
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
默认情况下,Flutter本地化将其翻译存储在ARB(应用程序资源包)文件中。这些只是像JSON一样的键值配对的文件。arb 让我们先为我们的默认英语创建一个名为app_en.arb 的文件,并将其放入lib/l10n/app_en.arb 。
由于我们要支持多种语言,我们必须为我们的应用程序支持的每一种语言创建一个单独的文件。在这篇文章中,我们将只支持英语和印地语作为一个例子。
你可以根据你想要支持的语言数量添加尽可能多的arb 文件。就目前而言,让我们做两个独立的arb 文件,因为在这个例子中我们只支持两个地区性语言。
lib/l10n/app_en.arb
{
"appTitle": "Demo App"
}
lib/l10n/app_hi.arb
{
"appTitle": "डेमो ऐप"
}
接下来,让我们把本地化添加到MaterialApp 。
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo'),
);
}
}
AppLocalizations.localizationsDelegates 是负责对我们的应用程序进行本地化。Flutter团队已经为Flutter部件、Material和Cupertino提供了本地化服务。例如,如果你使用 ,打开 ,你会发现对话已经被翻译成设备的当地语言,而不需要本地化文件。使用 ,Flutter只在检测到新的地区语言并将其添加到 's ,才会重建我们应用程序的用户界面。showDatePicker() DatePicker AppLocalizations.supportedLocales MaterialApp supportedLocales
为了支持iOS中的本地化,我们需要对Info.plist 进行以下修改。
<key>CFBundleLocalizations</key>
<array>
<string>en</string>
<string>hi</string>
</array>
本地化代码的生成
为了使用我们之前添加的ARB文件中的翻译,我们需要生成与ARB文件交替的Dart文件,可以在我们想使用本地化值的地方导入。要生成这些文件,只需在完成上述配置修改后启动应用程序。一旦代码生成完成,你应该看到以下文件。
.dart_tool/flutter_gen/gen_l10n/app_localizations.dart.dart_tool/flutter_gen/gen_l10n/app_localizations_en.dart.dart_tool/flutter_gen/gen_l10n/app_localizations_hi.dart
注意:如果本地化代码的生成没有自动发生,运行
flutter gen-l10n,就可以了。
如果你打开app_localizations.dart ,你会看到该文件包含一个抽象类AppLocalizations ,其中有localizationsDelegates 和supportedLocales ,以及你在ARB文件中添加的定位值。其他文件app_localizations_en.dart 和app_localizations_hi.dart 包含了扩展AppLocalizations 的类,这些类具有特定于本地的变量和方法。
让我们把我们的应用程序本地化
为了使用AppLocalizaions 类,你必须首先导入这个类。
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
之后,你可以使用AppLocalizations.of(context).appTitle 来访问locale值。我们的MaterialApp 现在看起来像这样。
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: AppLocalizations.of(context).appTitle),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Padding(
padding: EdgeInsets.only(top: 32),
child: Text(
'Flutter is Awesome',
style: TextStyle(fontSize: 24),
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('You have pushed this button :',
style: Theme.of(context).textTheme.headline6),
Text(
'$_counter times',
style: Theme.of(context).textTheme.headline4,
)
],
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
恭喜你,我们的应用程序的标题现在已经成功地被本地化了。我们只需要更新其他的String 值。
为国际化插值单词和短语
插值就是把某样东西插入另一样东西中。当你想让一个词或文本在所有支持的地区的默认语言(如英语)中出现时,插值在本地化中很有用。例如,在我们的演示应用程序中,我们想显示一段文字 "Flutter is awesome",但问题是我们想让Flutter这个词在用户的设备上无论使用什么语言都是英文。
让我们把插值的句子添加到我们的locale ARB文件中。
lib/l10n/app_en.arb:
{
"appTitle": "Demo App",
"appDescription": "{flutter} is Awesome",
"@appDescription": {
"placeholders": {
"flutter": {
"type": "String",
"example": "Flutter"
}
}
},
}
lib/l10n/app_hi.arb:
{
"appTitle": "डेमो ऐप",
"appDescription": "{flutter} बहुत बढ़िया है",
}
现在,我们要消耗我们添加到ARB文件中的插值文本描述。由于我们要在多个地方访问AppLocalizations ,我们将制作一个实例变量_locale ,并在didChangeDependencies() 中初始化它。
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
late AppLocalizations _local;
@override
void didChangeDependencies() {
_local = AppLocalizations.of(context);
super.didChangeDependencies();
}
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_local.appTitle),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 32),
child: Text(
_local.appDescription('Flutter'),
style: const TextStyle(fontSize: 24),
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("You have pushed this button :",
style: Theme.of(context).textTheme.headline6),
Text(
"$_counter",
style: Theme.of(context).textTheme.headline4,
)
],
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: "Increment",
child: const Icon(Icons.add),
),
);
}
}
运行应用程序,你会看到无论你的设备设置成什么语言,"Flutter "这个词都会是英文的。
单数和复数支持
在本地化过程中,我们经常要处理单数和复数的问题。例如 - "Congrats
, you won a coupon," 或者,"Congrats
, you won two coupon." 需要注意的是,不同的语言对复数的处理方式不同,在处理复数时你需要谨慎,因为你需要对你所翻译的语言有一些了解。
让我们进行必要的修改,以便在我们的本地化文件中支持复数。
lib/l10n/app_en.arb:
{
"appTitle": "Demo App",
"appDescription": "{flutter} is Awesome",
"@appDescription": {
"placeholders": {
"flutter": {
"type": "String",
"example": "Flutter"
}
}
},
"counterText": "You have pushed this button :",
"counter": "{count,plural, =0{0} =1{1 time} other{{count} times}}",
"@counter": {
"placeholders": {
"count": {
"type": "int",
"example": "count"
}
}
},
"counterButtonText": "Increment"
}
lib/l10n/app_hi.arb:
{
"appTitle": "डेमो ऐप",
"appDescription": "{flutter} बहुत बढ़िया है",
"counterText": "आपने यह बटन दबा दिया है :",
"counter": "{count,plural, =0{0} =1{1 बार} other{{count} बार}}",
"counterButtonText": "जोड़ें"
}
现在,我们已经在我们的两个ARB文件的关键counter ,并且还添加了counterButtonText ,将被用作增量按钮的工具提示,我们可以写这个。
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
late AppLocalizations _local;
@override
void didChangeDependencies() {
_local = AppLocalizations.of(context);
super.didChangeDependencies();
}
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_local.appTitle),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 32),
child: Text(
_local.appDescription('Flutter'),
style: const TextStyle(fontSize: 24),
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(_local.counterText,
style: Theme.of(context).textTheme.headline6),
Text(
_local.counter(_counter),
style: Theme.of(context).textTheme.headline4,
)
],
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: _local.counterButtonText,
child: const Icon(Icons.add),
),
);
}
}
注意我们是如何将_counter 值传递给AppLocalizations.counter() ,它最终将检查该值是单数还是复数,它将基于此返回一个String 值。
总结
在本教程中,你学会了如何将你的flutter应用程序本地化,使其更容易被用户接受。我希望你继续尝试新的东西
现在,我们已经把一切都准备好了,你所要做的就是运行应用程序并享受。
祝您好运!翩翩起舞快乐!
如果您有任何问题,请随时发表。我们欢迎任何反馈。