Flutter多语言支持插件multiple_localization_plus的使用

Flutter多语言支持插件multiple_localization_plus的使用

问题

如果你想要有多个arb文件,并且为每个文件注册单独的委托(delegate),那么你将面临一个问题。Intl包不允许多次调用initializeMessages。只有第一次调用会被处理,并且只会使用首次调用的消息。之后的调用将被忽略。

为什么我们需要多个arb文件?

在一般情况下,我们并不需要。只需将所有本地化字符串放在一个文件中即可。但如果你希望将带有arb文件的国际化添加到一个独立的包中,然后在你的项目中使用该包及其自己的本地化文件时,就会遇到问题。

MultipleLocalizations 支持使用 Localizations.override(delegates: [SomeLocalizationsDelegate(), ...]) 小部件。正是为了解决这种情况,开发了此包。

更多信息可以参见Medium上的文章:Dart包的本地化

使用方法

要使用此包,请在 pubspec.yaml 文件中将其作为依赖项添加:

dependencies:
  multiple_localization_plus: ^x.x.x

然后,在加载代理(delegate)时使用 MultipleLocalizations.load 方法,而不是显式调用 initializeMessages

示例

class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
  const _AppLocalizationsDelegate();

  [@override](/user/override)
  bool isSupported(Locale locale) {
    return ['en', 'ru'].contains(locale.languageCode);
  }

  [@override](/user/override)
  Future<AppLocalizations> load(Locale locale) {
    return MultipleLocalizations.load(
        initializeMessages, locale, (l) => AppLocalizations(l),
        setDefaultLocale: true);
  }

  [@override](/user/override)
  bool shouldReload(LocalizationsDelegate<AppLocalizations> old) {
    return false;
  }
}

覆盖来自包中的字符串

如果你想要覆盖项目中包内的字符串(例如更改包小部件中的某些标签),则需要在应用程序本地化类中定义具有所需名称的字符串。

示例

如果包内有一个名为 messageFromPackageForOverride 的字符串:

class PackageLocalizations {
  ...

  String get messageFromPackageForOverride =>
        Intl.message('Package', name: 'messageFromPackageForOverride');
}

那么你需要在 AppLocalizations 中定义 messageFromPackageForOverride

class AppLocalizations {
  ...

  String get messageFromPackageForOverride =>
        Intl.message('App', name: 'messageFromPackageForOverride');
}

确保在添加包本地化代理之前先添加应用程序本地化代理:

const MaterialApp(
  localizationsDelegates: [
    AppLocalizations.delegate,
    PackageLocalizations.delegate,
    DefaultCupertinoLocalizations.delegate,
  ],
  ...
)

现在,每当包使用 messageFromPackageForOverride 时,你将会看到 App,而不是 Package

设置回退语言环境

你还可以在加载应用程序本地化代理时指定一个回退语言环境。使用 [fallbackLocale] 参数设置一个在当前语言环境中找不到某些键时使用的语言环境。只有第一次调用 [load] 会设置回退语言环境,请确保应用程序的本地化代理作为委托列表的第一个元素添加。

注意,如果你提供了 [fallbackLocale],则会在应用程序启动时将所有消息加载到内存中,而不仅仅是当前语言环境。

完整示例代码

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:multiple_localization_plus/multiple_localization_plus.dart';

import './app/l10n/messages_all.dart';
import './package/l10n/messages_all.dart' as package;

void main() {
  runApp(
    const MaterialApp(
      supportedLocales: [Locale('en')],
      localizationsDelegates: [
        AppLocalizations.delegate,
        PackageLocalizations.delegate,
        DefaultCupertinoLocalizations.delegate,
      ],
      home: HomeScreen(),
    ),
  );
}

class HomeScreen extends StatelessWidget {
  const HomeScreen({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    final appLocalization = AppLocalizations.of(context);
    final packageLocalization = PackageLocalizations.of(context);
    return Scaffold(
      appBar: AppBar(
        title: Text(appLocalization.title),
      ),
      body: Padding(
        padding: const EdgeInsets.all(18.0),
        child: Center(
          child: Column(
            children: [
              Text(appLocalization.messageFromApp),
              Text(packageLocalization.messageFromPackage),
              Text(packageLocalization.messageFromPackageForOverride),
            ],
          ),
        ),
      ),
    );
  }
}

// 应用程序本地化

class _AppLocalizationsDelegate
    extends LocalizationsDelegate<AppLocalizations> {
  const _AppLocalizationsDelegate();

  [@override](/user/override)
  bool isSupported(Locale locale) => ['en'].contains(locale.languageCode);

  [@override](/user/override)
  Future<AppLocalizations> load(Locale locale) {
    return MultipleLocalizations.load(
        initializeMessages, locale, (l) => AppLocalizations(l),
        setDefaultLocale: true);
  }

  [@override](/user/override)
  bool shouldReload(LocalizationsDelegate<AppLocalizations> old) => false;
}

/// 应用程序本地化。
class AppLocalizations {
  /// 委托。
  static const LocalizationsDelegate<AppLocalizations> delegate =
      _AppLocalizationsDelegate();

  static AppLocalizations of(BuildContext context) =>
      Localizations.of<AppLocalizations>(context, AppLocalizations)!;

  final String locale;

  AppLocalizations(this.locale);

  String get title => Intl.message('Multiple localization', name: 'title');

  String get messageFromApp =>
      Intl.message('Default Message from App', name: 'messageFromApp');

  String get messageFromPackageForOverride =>
      Intl.message('Default overrided message from Package',
          name: 'messageFromPackageForOverride');
}

// 其他本地化,例如来自包

class _PackageLocalizationsDelegate
    extends LocalizationsDelegate<PackageLocalizations> {
  const _PackageLocalizationsDelegate();

  [@override](/user/override)
  bool isSupported(Locale locale) => ['en'].contains(locale.languageCode);

  [@override](/user/override)
  Future<PackageLocalizations> load(Locale locale) {
    return MultipleLocalizations.load(
        package.initializeMessages, locale, (l) => PackageLocalizations(l));
  }

  [@override](/user/override)
  bool shouldReload(LocalizationsDelegate<PackageLocalizations> old) => false;
}

/// 包本地化。
class PackageLocalizations {
  /// 委托。
  static const LocalizationsDelegate<PackageLocalizations> delegate =
      _PackageLocalizationsDelegate();

  static PackageLocalizations of(BuildContext context) =>
      Localizations.of<PackageLocalizations>(context, PackageLocalizations)!;

  final String locale;

  PackageLocalizations(this.locale);

  String get messageFromPackage =>
      Intl.message('Default Message from Package', name: 'messageFromPackage');

  String get messageFromPackageForOverride =>
      Intl.message('Default Message from Package for override',
          name: 'messageFromPackageForOverride');
}

更多关于Flutter多语言支持插件multiple_localization_plus的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter多语言支持插件multiple_localization_plus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,关于在Flutter项目中使用multiple_localization_plus插件来实现多语言支持,以下是一个具体的代码示例。这个示例将展示如何设置和使用multiple_localization_plus插件来实现应用的多语言切换。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加multiple_localization_plus依赖:

dependencies:
  flutter:
    sdk: flutter
  multiple_localization_plus: ^x.y.z  # 替换为最新版本号

然后运行flutter pub get来安装依赖。

2. 创建语言文件

在你的项目根目录下创建一个assets/locales文件夹,并在其中创建不同的语言文件,例如en.jsonzh.json

assets/locales/en.json:

{
  "greeting": "Hello",
  "farewell": "Goodbye"
}

assets/locales/zh.json:

{
  "greeting": "你好",
  "farewell": "再见"
}

3. 配置pubspec.yaml

pubspec.yaml中配置语言文件为资产:

flutter:
  assets:
    - assets/locales/en.json
    - assets/locales/zh.json

4. 创建Localizations类

创建一个新的Dart文件,例如locales.dart,来定义你的Localizations类:

import 'package:flutter/material.dart';
import 'package:multiple_localization_plus/multiple_localization_plus.dart';
import 'package:your_app_name/assets/locales/en.dart' as en;
import 'package:your_app_name/assets/locales/zh.dart' as zh;

class AppLocalizations {
  final Locale locale;
  AppLocalizations(this.locale);

  static AppLocalizations of(BuildContext context) {
    return Localizations.of<AppLocalizations>(context, AppLocalizations)!;
  }

  String get greeting {
    return MultipleLocalization.of(locale).translate(
      en.greeting,
      zh.greeting,
    );
  }

  String get farewell {
    return MultipleLocalization.of(locale).translate(
      en.farewell,
      zh.farewell,
    );
  }
}

class MultipleLocalizationDelegate extends LocalizationsDelegate<AppLocalizations> {
  const MultipleLocalizationDelegate();

  @override
  bool isSupported(Locale locale) {
    return ['en', 'zh'].contains(locale.languageCode);
  }

  @override
  Future<AppLocalizations> load(Locale locale) async {
    MultipleLocalization.load(locale, [
      Locale('en', ''),
      Locale('zh', ''),
    ]);

    // 这里需要手动加载json文件到内存中,并映射到Localizations中
    // 实际操作中,你可能需要创建一个工具类来动态加载这些文件
    // 这里为了简化,我们直接引用静态导入的json数据
    MultipleLocalization.setLocaleData(
      locale,
      en.data, // 英文数据
      zh.data, // 中文数据
    );

    return AppLocalizations(locale);
  }

  @override
  bool shouldReload(LocalizationsDelegate<AppLocalizations> oldDelegate) {
    return false;
  }
}

注意:上面的代码示例中,en.dartzh.dart应该包含从JSON文件解析的数据。你需要使用jsonDecode函数来解析这些JSON文件,并将结果存储在data变量中。例如:

// en.dart
import 'dart:convert';

final Map<String, String> data = jsonDecode('''
{
  "greeting": "Hello",
  "farewell": "Goodbye"
}
''');
// zh.dart
import 'dart:convert';

final Map<String, String> data = jsonDecode('''
{
  "greeting": "你好",
  "farewell": "再见"
}
''');

但在实际项目中,你可能希望动态加载这些文件而不是硬编码它们。

5. 使用LocalizationsDelegate

在你的MaterialApp中使用MultipleLocalizationDelegate

import 'package:flutter/material.dart';
import 'package:your_app_name/locales.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      localizationsDelegates: [
        MultipleLocalizationDelegate(),
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: [
        Locale('en', ''),
        Locale('zh', ''),
      ],
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  Locale _currentLocale;

  @override
  void initState() {
    super.initState();
    _currentLocale = Locale('en', ''); // 默认语言
  }

  void changeLanguage(Locale locale) {
    setState(() {
      _currentLocale = locale;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(AppLocalizations.of(context).greeting),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(AppLocalizations.of(context).farewell),
            ElevatedButton(
              onPressed: () => changeLanguage(Locale('zh', '')),
              child: Text('切换到中文'),
            ),
            ElevatedButton(
              onPressed: () => changeLanguage(Locale('en', '')),
              child: Text('切换到英文'),
            ),
          ],
        ),
      ),
    );
  }
}

总结

上面的代码展示了如何使用multiple_localization_plus插件在Flutter应用中实现多语言支持。需要注意的是,在实际项目中,你可能需要处理更复杂的语言文件加载逻辑,以及可能的异步操作。此外,你可能还需要处理其他UI组件的本地化,例如日期、数字和货币格式等。

回到顶部