5.8 Flutter 国际化与本地化 (Internationalization and Localization)

arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart

plaintext
复制代码

在 `lib/l10n` 目录下创建 `app_en.arb`:

```json
{
  "@@locale": "en",
  "appTitle": "Counter App",
  "counterText": "You have pushed the button this many times:",
  "incrementButton": "Increment",
  "resetButton": "Reset",
  "countMessage": "{count, plural, =0{No clicks yet} =1{One click} other{{count} clicks}}",
  "@countMessage": {
    "placeholders": {
      "count": {
        "type": "int"
      }
    }
  }
}

lib/l10n 目录下创建 app_zh.arb

json
复制代码
{
  "@@locale": "zh",
  "appTitle": "计数器应用",
  "counterText": "您已点击按钮这么多次:",
  "incrementButton": "增加",
  "resetButton": "重置",
  "countMessage": "{count, plural, =0{还没有点击} =1{点击了一次} other{点击了 {count} 次}}"
}

步骤 3: 生成本地化代码

运行命令:

bash
复制代码
flutter gen-l10n

这会在 lib/generated 目录下生成 app_localizations.dart 等文件。

步骤 4: 构建 UI 界面 (lib/main.dart)

dart
复制代码
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:multi_language_counter/generated/app_localizations.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      // 配置本地化委托和支持的语言环境
      localizationsDelegates: const [
        AppLocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: const [
        Locale('en', ''), // English
        Locale('zh', ''), // Chinese
      ],
      // 设置应用的标题,使用本地化字符串
      onGenerateTitle: (context) => AppLocalizations.of(context)!.appTitle,
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  void _resetCounter() {
    setState(() {
      _counter = 0;
    });
  }

  @override
  Widget build(BuildContext context) {
    // 获取本地化字符串实例
    final AppLocalizations localizations = AppLocalizations.of(context)!;

    return Scaffold(
      appBar: AppBar(
        title: Text(localizations.appTitle),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              localizations.counterText,
            ),
            Text(
              localizations.countMessage(_counter), // 使用带参数的本地化字符串
              style: Theme.of(context).textTheme.headlineMedium,
            ),
            const SizedBox(height: 20),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: _resetCounter,
                  child: Text(localizations.resetButton),
                ),
                const SizedBox(width: 10),
                ElevatedButton(
                  onPressed: _incrementCounter,
                  child: Text(localizations.incrementButton),
                ),
              ],
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: localizations.incrementButton,
        child: const Icon(Icons.add),
      ),
    );
  }
}

案例分析:

  • pubspec.yaml 配置flutter_localizations 依赖和 generate: true 是启用 Flutter 国际化机制的关键。
  • l10n.yaml 配置:指定了 arb 文件的目录、模板文件和生成的 Dart 文件名。
  • arb 文件
    • @@locale:指定当前文件的语言环境。
    • appTitle, counterText, incrementButton, resetButton:简单的键值对,直接映射到本地化字符串。
    • greetingcountMessage:带有参数的字符串。{name}{count} 是占位符。@greeting@countMessage 提供了关于占位符的元数据。
    • plural (复数) 规则:{count, plural, =0{...} =1{...} other{...}} 允许根据数字的不同值显示不同的复数形式。这对于不同语言的复数规则非常重要。
  • flutter gen-l10n 命令:这个命令会自动解析 arb 文件,并生成 AppLocalizations 类及其相关的本地化委托。这个类提供了访问所有本地化字符串的方法。
  • MaterialApp 配置
    • localizationsDelegates:包含了 AppLocalizations.delegate (你的应用本地化) 和其他 Flutter 内置 Widget 的本地化委托。
    • supportedLocales:列出了你的应用支持的所有语言环境。Flutter 会根据用户的设备语言偏好,从这个列表中选择最匹配的语言。
    • onGenerateTitle:一个回调函数,用于在 MaterialApp 首次构建时设置应用的标题,确保标题也是本地化的。
  • 在 Widget 中使用:通过 AppLocalizations.of(context)! 获取 AppLocalizations 实例,然后就可以像调用普通方法一样访问本地化字符串,例如 localizations.appTitlelocalizations.countMessage(_counter)

通过这个案例,你将掌握 Flutter 国际化和本地化的整个流程,从配置到实际使用。这使得你的应用能够轻松地支持多种语言,为全球用户提供更好的体验。