Flutter中的国际化与本土化区别
fullstacker 发布于 2021-02-17

国际化(i18n)和本地化(l10n)这两个词经常被错误地互换使用。

本地化是将你的应用程序提供给其他地区的过程。它包括定义用户语言、地区和任何特定变体的参数,例如en-US(美式英语)。
听起来很简单,但你怎么做到的?是否为每种语言创建代码副本?或者在选择要显示的文本的地方添加if语句?不,这就是国际化的救星。
国际化是您设计代码以使其易于本地化的方式。所以,是的,你可以有一个国际化的应用程序,只支持一个地区,因为它有能力最终支持多个地区没有戏剧性的工程努力。事实上,这是值得鼓励的。国际化,即使你的应用程序计划中没有成为通晓多种语言的人。它将使您的代码更干净,更经得起未来的考验。
接下来,您将看到如何使用Flutter来国际化应用程序。

Flutter中的国际化

为应用程序的每个可翻译文本创建一个包含动态字符串属性或函数的类。例如,formPageAppBarTitle属性可能返回'Death by Caffeine Calculator'或'Calculadora de Morte por Cafeína',具体取决于区域设置。

创建一个中介类,负责在应用程序初始化或区域设置更改时设置在上一步中创建的类的实例。
向MaterialApp中的Localizations小部件提供这个中介类的实例。
用新的动态版本替换硬编码文本。例如,Text('Death by Caffeine Calculator')变成Text(本地化<classfromFirstStepContainingValuesthatVaryPerLocale>(上下文,classfromFirstStepContainingValuesthatVaryPerLocale).formPageAppBarTitle)。
尽管第一步中的类包含的值varyperLocale是一个有意义的名称,但肯定的是,它相当长,而且您要输入很多。从现在起,你就叫它S。


维护翻译

剩下的问题是:S应该如何存储所有受支持语言的字符串?
这就是您所说的实现细节,因此,这取决于您。但这里有一些想法:
使用Map<String,Map<String,String>>,其中第一个Map的键是语言,第二个Map的键是文本的ID,例如formPageAppBarTitle。
维护和读取类似JSON的文件,每个区域设置一个。
发挥你的创造力。
第二种方法看起来是一个很好的选择,您将在本教程中使用它。您将依靠Intl包来帮助您从文件中读取值。
将内容与逻辑分开,可以保持代码整洁,甚至可以让非编码人员更改代码。

即使有国际的帮助,你还有很多工作要做。每次输入新语言时更改委托,每次需要添加新字符串时更改代理的过程(这种情况经常发生)既繁琐又自动化。
如你所知,消除繁琐和机器人的任务是一个开发人员的超级能力。这就是为什么Localizely的人为androidstudio和visualstudio代码创建了一个令人兴奋的flatter Intl插件来为您处理这些任务。
每当您添加新的语言或字符串时,插件都会为您生成一个新的LocalizationsDelegate和S。
注意:不要混淆Intl包和flatterintlide插件。后者处理生成使用前者的类。在本教程中,您将使用这两种方法。

安装Flutter Intl

在macOS上按Command-,(逗号),在Linux或Windows上按Control-Alt-s,打开Android Studio的首选项。
选择左侧面板(1)上的插件和上部选项卡栏(2)上的市场。在搜索栏(3)中键入intl,然后单击Install以获得Localizely的flatter intl结果(4)。

插件安装好之后重启IDE,


生成类
打开 pubspec.yaml 并替换#TODO:在此处添加intl和flatterŠu本地化。使用:

intl: 0.16.1
flutter_localizations:
  sdk: flutter
您刚刚向项目中添加了两个包:
国际语言:用于i18n和l10n的工具,例如消息翻译、日期/数字格式化和解析。您将主要通过生成的类来处理这个包。
Flutter本地化:抓紧!你马上就会了解更多。

在项目目录中选择starter文件夹,然后在菜单栏上为项目选择Tools▸flutter Intl▸Initialize。


上面的命令为您的出版规范. 将main_locale:en_US添加到其下面,并在相同的缩进级别enabled:true中。

flutter_intl:
  main_locale: en_US
  enabled: true

在屏幕顶部的flUtter命令栏中单击Pub get。
返回IDE菜单栏上的Tools▸flutter Intl,但这次选择Remove Locale。选择en并单击OK。
                                                               

在这里,您将默认区域设置从en更改为en\u US,正确地识别了细微差别。这将允许您稍后基于国家代码执行自定义逻辑。
插件在lib中创建了两个文件夹,包括一些文件:
generated:保存生成的类。你不需要碰它们。
l10n:your.arbs的主页,JSON语法文件将保存您的翻译。美国英语的那个已经在那里了。
既然您已经设置了flatter Intl,现在是时候配置您的应用程序来使用它了。

配置应用程序
转到lib/main.dart,并将这两个导入添加到其他导入的下面:

import 'package:buzzkill/generated/l10n.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
现在,在MaterialApp中,remove//TODO:指定localizationsDelegates和supportedLocales。加上这个:

 localizationsDelegates: [
  // 1
  S.delegate,
  // 2
  GlobalMaterialLocalizations.delegate,
  GlobalWidgetsLocalizations.delegate,
  GlobalCupertinoLocalizations.delegate,
],
supportedLocales: S.delegate.supportedLocales,
以下是您所做的:
还记得中间类吗?负责设置S实例的代理?插件为您生成了它,您可以在这里使用它。
不仅你的应用程序的文本需要翻译,一些flatter小部件也需要翻译。负责它们的代理来自您在上面添加的flutter_localizations包。
回到菜单栏,Tools ▸ Flutter Intl ▸ Add Locale. Type in pt_BR ,然后单击“确定”。
                                                                   

lib/l10n文件夹现在包含一个新文件-intl\u pt_BR.arb公司-你的应用程序的Android版本已经可以支持en-US和pt-BR了。
只有Android版本?不是iOS?是的!这是因为一个特定的iOS配置文件需要您特别小心。好消息是您不需要Xcode来完成它。
在项目结构中,打开ios/Runner/信息列表并替换<!--TODO:指定支持的区域设置。-->使用:

<key>CFBundleLocalizations</key>
<array>
    <string>en_US</string>
    <string>pt_BR</string>
</array>
停止应用程序的上一次执行,然后重新生成并运行它,以确保没有引入任何错误。不要期望任何视觉变化。

提取字符串
替换lib/l10n/intl_en_US.arb

 {
  "@@locale": "en_US",
  "formPageAppBarTitle": "Death by Caffeine Calculator",
  "firstSuggestedDrinkName": "Drip Coffee (Cup)",
  "secondSuggestedDrinkName": "Espresso (Shot)",
  "thirdSuggestedDrinkName": "Latte (Mug)",
  "formPageWeightInputLabel": "Body Weight",
  "formPageWeightInputSuffix": "pounds",
  "formPageRadioListLabel": "Choose a drink",
  "formPageActionButtonTitle": "CALCULATE",
  "formPageCustomDrinkRadioTitle": "Other",
  "formPageCustomDrinkServingSizeInputLabel": "Serving Size",
  "formPageCustomDrinkServingSizeInputSuffix": "fl. oz",
  "formPageCustomDrinkCaffeineAmountInputLabel": "Caffeine",
  "formPageCustomDrinkCaffeineAmountInputSuffix": "mg",
  "resultsPageAppBarTitle": "Dosages",
  "resultsPageLethalDosageTitle": "Lethal Dosage",
  "resultsPageFirstDisclaimer": "*Based on {servingSize} fl. oz serving.",
  "resultsPageLethalDosageMessage": "{quantity, plural, one{One serving.} other{{formattedNumber} servings in your system at one time.}}",
  "resultsPageSafeDosageTitle": "Daily Safe Maximum",
  "resultsPageSafeDosageMessage": "{quantity, plural, one{One serving per day.} other{{formattedNumber} servings per day.}}",
  "resultsPageSecondDisclaimer": "*Applies to age 18 and over. This calculator does not replace professional medical advice."
}
这些是buzzkill中每个可见文本行的en-US条目。特别注意:
@@locale:标识文件的区域设置。如果您不添加它,Intl可以从文件名中推断出来,但它会给您一个警告。
resultsPageFirstDisclaimer:{servingSize}是占位符。S动态地用您在使用它生成的函数时指定的值替换它。
resultsPageLethalDosageMessage和resultsPageSafeDosageMessage:它们是复数。它们的值取决于调用函数时指定的数字。除此之外,它们还使用{formattedNumber}占位符,如resultsPageFirstDisclaimer。
别担心!当您看到这些概念反映在Dart方面时,它们更容易理解。
注意:你不应该重复使用条目,这就是为什么你以它们在你的应用程序中出现的位置命名它们。根据上下文的不同,同一个字符串可以有不同的翻译。
现在您已经为美式英语设置了.arb文件,是时候将巴西葡萄牙语版本添加到buzzkill了。


添加巴西葡萄牙语翻译

这次,在 lib/l10n/intl_pt_BR.arb,将所有内容替换为:

 {
  "@@locale": "pt_BR",
  "formPageAppBarTitle": "Calculadora de Morte por Cafeína",
  "firstSuggestedDrinkName": "Café Coado (Xícara)",
  "secondSuggestedDrinkName": "Espresso (Shot)",
  "thirdSuggestedDrinkName": "Latte (Caneca)",
  "formPageWeightInputLabel": "Peso Corporal",
  "formPageWeightInputSuffix": "libras",
  "formPageRadioListLabel": "Escolha uma bebida",
  "formPageActionButtonTitle": "CALCULAR",
  "formPageCustomDrinkRadioTitle": "Outra",
  "formPageCustomDrinkServingSizeInputLabel": "Tamanho",
  "formPageCustomDrinkServingSizeInputSuffix": "fl. oz",
  "formPageCustomDrinkCaffeineAmountInputLabel": "Cafeína",
  "formPageCustomDrinkCaffeineAmountInputSuffix": "mg",
  "resultsPageAppBarTitle": "Dosagens",
  "resultsPageLethalDosageTitle": "Dose Letal",
  "resultsPageLethalDosageMessage": "{quantity, plural, one{Uma porção.} other{{formattedNumber} porções no seu sistema de uma vez.}}",
  "resultsPageSafeDosageTitle": "Limite Seguro Diário",
  "resultsPageSafeDosageMessage": "{quantity, plural, one{Uma porção por dia.} other{{formattedNumber} porções por dia.}}",
  "resultsPageFirstDisclaimer": "*Baseado em uma porção de {servingSize} fl. oz.",
  "resultsPageSecondDisclaimer": "*Se aplica a pessoas com 18 anos ou mais. Essa calculadora não substitui conselhos médicos profissionais."
}
这里没有什么新鲜事。这些是相同lib/l10n/intl\en的葡萄牙语翻译_美国arb条目。
通过在macOS上使用Command-S或在Linux或Windows上使用Control-S保存文件,触发类重新生成。
重新生成并运行。一切看起来都应该和以前一样,现在您已经准备好编写真正的代码了。
您已经完成了很多工作,但是在您从小部件中删除硬编码值之前,应用程序不会反映您的更改。

删除硬编码值

你的旅程从lib/pages/form_page.dart,巴斯·基尔的家。打开文件,在imports块的顶部添加以下行:

import 'package:buzzkill/generated/l10n.dart';
用户界面向用户提供三种建议的含咖啡因饮料。在代码中,您可以通过_drinkSuggestions控制它们。删除当前的_drinkSuggestions定义并添加以下内容:

 // 1
List<Drink> _drinkSuggestions;

// 2
Locale _userLocale;

@override
void didChangeDependencies() {
  // 3
  final newLocale = Localizations.localeOf(context);
  
  if (newLocale != _userLocale) {
    _userLocale = newLocale;
    // 4
    _weightTextController.clear();
    _servingSizeTextController.clear();
    _caffeineTextController.clear();
    _selectedDrinkSuggestion = null;
    _drinkSuggestions = [
      Drink(
        // 5
        name: S.of(context).firstSuggestedDrinkName,
        caffeineAmount: 145,
        servingSize: 8,
      ),
      Drink(
        name: S.of(context).secondSuggestedDrinkName,
        caffeineAmount: 77,
        servingSize: 1.5,
      ),
      Drink(
        name: S.of(context).thirdSuggestedDrinkName,
        caffeineAmount: 154,
        servingSize: 16,
      ),
    ];
  }
  super.didChangeDependencies();
}
全栈者
关注 私信
文章
31
关注
0
粉丝
0