到目前为止,我正在使用动态字符串,如这篇文章的解决方案所示: Flutter internationalization - Dynamic strings
这是一个例子:
AppLocalizations.of(context).userAge(18)
在AppLocalizations.dart上:
userAge(age) => Intl.message(
"My age is $age",
name: "userAge",
args: [age]);
// Return "My age is 18"
但是我随后阅读了有关颤振国际化的这篇文章:https://medium.com/flutter-community/flutter-internationalization-the-easy-way-using-provider-and-json-c47caa4212b2 其中显示了如何使用json文件作为字符串的资源文件进行本地化。看起来更方便,所以我更喜欢使用此方法,但不知道如何从具有动态值的json文件中获取字符串。
有解决方案吗?
答案 0 :(得分:6)
在您的json
目录中创建一个文件夹assets
。将您的语言文件放入其中。
assets
json
- en.json // for English
- ru.json // for Russian
现在在en.json
中,输入您的字符串。
{
"myAge": "My age is"
}
类似地,在ru.json
中,
{
"myAge": "Мой возраст"
}
将此添加到pubspec.yaml
文件中(注意空格)
flutter:
uses-material-design: true
assets:
- assets/json/
运行flutter pub get
已完成初始工作。让我们转到代码端。
将此样例代码复制到您的文件中:
Map<String, dynamic> language;
class AppLocalizations {
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
String getText(String key) => language[key];
String userAge(int age) => '${getText('myAge')} $age';
}
class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const AppLocalizationsDelegate();
@override
bool isSupported(Locale locale) => ['en', 'ru'].contains(locale.languageCode);
@override
Future<AppLocalizations> load(Locale locale) async {
final string = await rootBundle.loadString('assets/json/${locale.languageCode}.json');
language = json.decode(string);
return SynchronousFuture<AppLocalizations>(AppLocalizations());
}
@override
bool shouldReload(AppLocalizationsDelegate old) => false;
}
在MaterialApp
小部件中设置一些内容:
void main() {
runApp(
MaterialApp(
locale: Locale('ru'), // switch between "en" and "ru" to see effect
localizationsDelegates: [const AppLocalizationsDelegate()],
supportedLocales: [const Locale('en'), const Locale('ru')],
home: HomePage(),
),
);
}
现在,您可以简单地使用上面的委托:
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
var age = AppLocalizations.of(context).userAge(18);
// prints "My age is 18" for 'en' and "Мой возраст 18" for 'ru' locale.
print(age);
return Scaffold();
}
}
答案 1 :(得分:5)
要从JSON文件中获取具有动态值的字符串,您可以使用
final age = 18 //user input.
final ageString = 'user_age'
.localisedString()
.replaceAll(new RegExp(r'\${age}'), age)
en.json
{
"user_age": "My age is ${age}",
"user_name_age": "My name is ${name} and age is ${age}"
}
string_extension.dart
extension Localisation on String {
String localisedString() {
return stringBy(this) ?? '';
}
}
此外,您可以执行类似的操作
String localisedString(Map<String, String> args) {
String str = localisedString();
args.forEach((key, value) {
str = str.replaceAll(new RegExp(r'\${'+key+'}'), value);
});
return str;
}
//usecase
final userName = 'Spider Man'
final age = '18'
final nameAgeString = 'user_name_age'.localisedString({'name': userName, 'age': age})
app_localisation.dart
Map<String, dynamic> _language;
String stringBy(String key) => _language[key] as String ?? 'null';
class AppLocalisationDelegate extends LocalizationsDelegate {
const AppLocalisationDelegate();
// override the following method if you want to specify the locale you are supporting.
final _supportedLocale = ['en'];
@override
bool isSupported(Locale locale) => _supportedLocale.contains(locale.languageCode);
@override
Future load(Locale locale) async {
String jsonString = await rootBundle
.loadString("assets/strings/${locale.languageCode}.json");
_language = jsonDecode(jsonString) as Map<String, dynamic>;
print(_language.toString());
return SynchronousFuture<AppLocalisationDelegate>(
AppLocalisationDelegate());
}
@override
bool shouldReload(AppLocalisationDelegate old) => false;
}
答案 2 :(得分:3)
我已经尝试了各种解决方案来实现本地化,并且碰到的最好的是VS Code(不隶属)为Android Studio/IntelliJ或Localizely.com制作的Flutter Intl插件。
有了它,基本上,您可以使用市场/插件库安装插件,然后使用菜单选项为您的项目初始化。这样会在lib / l10n / intl_en.arb中创建一个默认的英语语言环境(听起来很吓人,但实际上只是JSON),并为lib/generated
中的国际化设置了所有支架。
还必须将以下内容添加到依赖项中。
flutter_localizations:
sdk: flutter
然后,您可以通过导入generated/l10n.dart
(其中包含一个名为S的类),将密钥添加到此文件,它们将在您的应用中自动可用。
无论您是在初始化MaterialApp的任何地方,都要使它颤抖地使用它,请确保将S.delegate
传递到MaterialApp的localizationsDelegates参数中(最有可能是带有GlobalMaterialLocalizations.delegate
,{{1 }},可能还有GlobalWidgetsLocalizations.delegate
。)您还必须向MaterialApp的GlobalCupertinoLocalizations.delegate
添加S.delegate.supportedLocales
。
要添加更多语言环境,请使用菜单中的选项(至少在intellij中),或简单地创建更多intl_.arb文件,插件将自动识别出该内容并设置相关代码。
假设您有一个包含以下内容的intl_en文件:
supportedLocales
然后您将使用{ "name": "Name" }
在代码中使用字符串。
在localizely的网站上更雄辩地解释了所有这些内容。
现在,要在这些.arb文件中使用密钥,只需要将其包装在{...}中。例如:
S.of(context).name
将导致使用{ "choose1OfNumOptions": "Choose 1 of {numoptions} options" }
。我不知道该插件支持完整的ARB specification,但它至少支持基础知识。
此外,我并没有使用Localizely,但它似乎是管理翻译和自动集成插件的一种非常有用的方法,尽管我认为它的定价也非常高-至少对于我的应用而言,这种情况经常发生有大量文字。实际上,我实际上只有一个google工作表,用于存储所有翻译,当需要更新时,我将其下载为.tsv并编写了一个简单的小解析器以写入.arb文件。
答案 3 :(得分:1)
{
"contactDetailsPopupEmailCopiedMessage": "Copied {email} to clipboard",
"@contactDetailsPopupEmailCopiedMessage": {
"description": "Message being displayed in a snackbar upon long-clicking email in contact details popup",
"placeholders": {
"email": {
"type": "String",
"example": "example@gmail.com"
}
}
}
}
abstract class AppLocalizations {
/// Message being displayed in a snackbar upon long-clicking email in contact details popup
///
/// In en, this message translates to:
/// **'Copied {email} to clipboard'**
String contactDetailsPopupEmailCopiedMessage(String email);
}
l10n.contactDetailsPopupEmailCopiedMessage("example@gmail.com")
有关详细信息,请查看here。