欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

在这里插入图片描述

前言

在 Flutter 应用开发中,国际化(i18n)是一个不可忽视的环节。虽然官方的 flutter_localizations 提供了基础支持,但在大型项目中,手动维护 key-value 映射不仅繁琐,还容易出错(如拼写错误、参数遗漏)。

slang (原 fast_i18n) 提供了一种类型安全、轻量级且功能强大的解决方案。它通过代码生成技术,将翻译文件转换为强类型的 Dart 类,从而在编译期就能发现错误,并提供极佳的 IDE 自动补全体验。本文将介绍如何在 OpenHarmony 项目中集成并使用 slang

一、slang 简介

1.1 核心优势

  • 类型安全:再也不用担心拼错 key 或传错参数类型。
  • 格式丰富:支持 JSON, YAML, CSV, ARB 格式。
  • 功能强大:支持复数、性别选择、参数插值、富文本等。
  • 零运行时依赖:生成的代码不依赖任何第三方库(除了 Flutter 本身),体积极小。

1.2 OpenHarmony 适配情况

slang 核心逻辑在于代码生成,生成的纯 Dart 代码可以在任何支持 Dart 的平台上运行,因此完美兼容 OpenHarmony。

slang_build_runner 代码生成

在 UI 组件中使用

多语言翻译文件 (YAML/JSON)

生成的 Dart 代码

强类型 API 接口 (Strongly Typed API)

鸿蒙端的 Flutter 应用

二、集成与配置

2.1 添加依赖

pubspec.yaml 中配置依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations: # 官方本地化支持
    sdk: flutter
  slang: ^3.25.0 # 运行时核心(可选,如果使用 generated code only 模式可不引)
  slang_flutter: ^3.25.0 # Flutter 集成工具

dev_dependencies:
  slang_build_runner: ^3.25.0 # 代码生成器
  build_runner: any

2.2 配置 slang.yaml

在项目根目录创建 slang.yaml 文件(可选,但推荐):

base_locale: zh
fallback_strategy: base_locale
input_directory: lib/i18n
input_file_pattern: .i18n.yaml
output_directory: lib/i18n
output_file_name: translations.g.dart
namespaces: true # 启用命名空间,便于模块化管理

2.3 创建翻译文件

lib/i18n 目录下创建文件(以 YAML 为例):

strings_zh.i18n.yaml (中文-基准):

main:
  title: slang 鸿蒙示例
  hello: 你好, OpenHarmony!
  welcome: 欢迎来到 $name 的应用
  clickMe: 点击次数 @:main.counter
  counter:
    other: $count 次

strings_en.i18n.yaml (英文):

main:
  title: slang OHOS Example
  hello: Hello, OpenHarmony!
  welcome: Welcome to $name's app
  clickMe: Click count @:main.counter
  counter:
    one: $count time
    other: $count times

2.4 生成代码

运行生成命令:

dart run build_runner build -d

三、核心 API 详解与示例

3.1 示例一:初始化与基础调用

main.dart 中初始化配置,并使用生成的 t 变量访问翻译。

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'i18n/translations.g.dart'; // 导入生成的文件

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  LocaleSettings.useDeviceLocale(); // 使用设备语言
  runApp(TranslationProvider(child: const MyApp()));
}

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      locale: TranslationProvider.of(context).flutterLocale, // 监听语言变化
      supportedLocales: AppLocaleUtils.supportedLocales,
      localizationsDelegates: GlobalMaterialLocalizations.delegates,
      home: const HomePage(),
    );
  }
}

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

  
  Widget build(BuildContext context) {
    // 使用 t 变量访问翻译
    return Scaffold(
      appBar: AppBar(title: Text(t.main.title)),
      body: Center(child: Text(t.main.hello)),
    );
  }
}

在这里插入图片描述

3.2 示例二:带参数与复数形式

slang 自动处理参数插值和复数逻辑。

import 'package:flutter/material.dart';
import 'i18n/translations.g.dart';

Widget buildContent(String userName, int count) {
  return Column(
    children: [
      // 参数插值
      Text(t.main.welcome(name: userName)),
      
      // 复数形式与链接引用
      // "clickMe": "点击次数 @:main.counter"
      // "counter": { "other": "$count 次" }
      Text(t.main.clickMe(count: count)),
    ],
  );
}

在这里插入图片描述

3.3 示例三:动态切换语言

你可以随时在应用内切换语言,无需重启。

import 'package:flutter/material.dart';
import 'i18n/translations.g.dart';

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

  
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        ElevatedButton(
          onPressed: () {
            // ✅ 推荐:直接调用 setLocale
            LocaleSettings.setLocale(AppLocale.zh);
          },
          child: const Text('中文'),
        ),
        const SizedBox(width: 20),
        ElevatedButton(
          onPressed: () {
            LocaleSettings.setLocale(AppLocale.en);
          },
          child: const Text('English'),
        ),
      ],
    );
  }
}

在这里插入图片描述

四、OpenHarmony 平台适配

4.1 字体适配

在多语言环境中,不同语言可能需要不同的字体。在 OpenHarmony 上,建议使用 ThemeDatafontFamilyFallback 来确保字符正确显示。

ThemeData(
  fontFamily: 'HarmonyOS Sans', // OpenHarmony 默认字体
  fontFamilyFallback: const ['Roboto', 'Noto Sans SC'],
)

4.2 日期格式化适配

slang 专注于字符串翻译。对于日期格式化,通常配合 intl 包使用。OpenHarmony 上使用 intl 需要确保初始化数据正确加载(通常无需额外操作,Dart SDK 已内置)。

五、完整实战示例:多语言计数器

本示例展示一个包含语言切换、带参数文本和复数处理的完整计数器应用。

5.1 示例代码

请确保已按步骤 2.3 创建好 strings_zh.i18n.yamlstrings_en.i18n.yaml 并运行了代码生成。

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'i18n/translations.g.dart'; // 确保路径正确

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  LocaleSettings.useDeviceLocale(); 
  runApp(TranslationProvider(child: const SlangDemoApp()));
}

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      locale: TranslationProvider.of(context).flutterLocale,
      supportedLocales: AppLocaleUtils.supportedLocales,
      localizationsDelegates: GlobalMaterialLocalizations.delegates,
      title: 'Slang Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        useMaterial3: true,
      ),
      home: const CounterPage(),
    );
  }
}

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

  
  State<CounterPage> createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int _counter = 0;

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

  
  Widget build(BuildContext context) {
    // 获取当前语言下的翻译对象
    final translations = t.main;

    return Scaffold(
      appBar: AppBar(
        title: Text(translations.title), // 类型安全访问
        actions: [
          PopupMenuButton<AppLocale>(
            onSelected: (locale) {
              LocaleSettings.setLocale(locale); // 切换语言
            },
            itemBuilder: (context) => [
              const PopupMenuItem(
                value: AppLocale.zh,
                child: Text('简体中文'),
              ),
              const PopupMenuItem(
                value: AppLocale.en,
                child: Text('English'),
              ),
            ],
            icon: const Icon(Icons.language),
          ),
        ],
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              translations.hello,
              style: Theme.of(context).textTheme.headlineSmall,
            ),
            const SizedBox(height: 20),
            Text(
              translations.welcome(name: 'Developer'),
              style: const TextStyle(fontSize: 16, color: Colors.grey),
            ),
            const SizedBox(height: 40),
            Text(
              translations.clickMe(count: _counter), // 自动处理复数逻辑
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

在这里插入图片描述

六、总结

slang 以其类型安全和极佳的开发体验,成为 Flutter 国际化的优秀选择。在 OpenHarmony 平台上,它无需额外适配即可完美运行。

最佳实践

  1. 尽早配置 slang,避免后期大量字符串替换工作。
  2. 利用 namespaces 功能将大型项目的翻译文件拆分管理。
  3. 结合 IDE 插件,享受自动补全带来的效率提升。
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐