【Flutter for OpenHarmony】intl 国际化与多语言支持的鸿蒙化适配与实战指南

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


一、为什么我要做国际化?

我是 IntMainJhy,上海某高校大一计算机专业的学生。说起国际化(i18n),我一开始完全没想过要加这个功能,总觉得自己写的小众 App 只用中文就够了,没必要搞多语言。

后来室友问我:“你这个 App 能改成英文的吗?我想让我的外国朋友也用用。”

我才意识到,我的 App 完全是"中文特供",没有任何国际化支持。而且现在我一直在做 Flutter for OpenHarmony 鸿蒙应用开发,想要上架鸿蒙应用市场、面向更多用户,多语言国际化是必备功能。于是我从零开始研究 Flutter 官方 intl 国际化方案,踩了不少坑,也整理出一套能直接在鸿蒙设备上跑通的完整实战流程。


二、intl 介绍

2.1 什么是 intl?

intl 是 Flutter 官方提供的国际化核心包,配合 flutter_localizations 可以快速实现 App 多语言切换、文字本地化、日期时间格式化等功能,完美兼容 Flutter for OpenHarmony 鸿蒙平台

# pubspec.yaml
dependencies:
  intl: ^0.19.0
  flutter_localizations:
    sdk: flutter

2.2 核心概念

概念 说明
.arb 文件 标准翻译资源文件,存放多语言文本
Intl 处理文本、日期、数字格式化
Localizations 本地化资源加载管理器
l10n.yaml 国际化生成配置文件

三、项目完整配置

3.1 pubspec.yaml 完整配置

name: mental_health_app
description: Flutter鸿蒙国际化实战项目
version: 1.0.0+1

environment:
  sdk: '>=3.0.0 <4.0.0'

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: ^0.19.0
  provider: ^6.1.1
  shared_preferences: ^2.2.2

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:
  uses-material-design: true
  generate: true  # 必须开启,自动生成多语言代码

3.2 l10n.yaml 配置

在项目根目录新建 l10n.yaml,和 pubspec.yaml 同级:

arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
output-class: AppLocalizations
nullable-getter: false

3.3 创建翻译 arb 文件

先新建文件夹:lib/l10n

// lib/l10n/app_en.arb
{
  "@@locale": "en",
  "appTitle": "Mental Health",
  "moodRecord": "Mood Record",
  "meditation": "Meditation",
  "quiz": "Psychology Test",
  "breathing": "Breathing Training",
  "settings": "Settings",
  "happy": "Happy",
  "calm": "Calm",
  "neutral": "Normal",
  "sad": "Sad",
  "tired": "Tired",
  "startMeditation": "Start Meditation",
  "stopMeditation": "Stop Meditation",
  "recordMood": "Record Mood",
  "noData": "No data yet",
  "loading": "Loading...",
  "language": "Language",
  "systemFollow": "Follow System"
}
// lib/l10n/app_zh.arb
{
  "@@locale": "zh",
  "appTitle": "心理健康",
  "moodRecord": "心情记录",
  "meditation": "冥想",
  "quiz": "心理测试",
  "breathing": "呼吸训练",
  "settings": "设置",
  "happy": "开心",
  "calm": "平静",
  "neutral": "一般",
  "sad": "难过",
  "tired": "疲惫",
  "startMeditation": "开始冥想",
  "stopMeditation": "停止冥想",
  "recordMood": "记录心情",
  "noData": "暂无数据",
  "loading": "加载中...",
  "language": "语言设置",
  "systemFollow": "跟随系统"
}

3.4 生成多语言代码

终端执行命令,自动生成国际化代码:

flutter gen-l10n

执行成功后会自动生成 .dart 国际化文件,直接可在项目中引用。


四、国际化全局 LocaleProvider

// lib/mental_health/providers/locale_provider.dart
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

/// 全局语言状态管理
class LocaleProvider extends ChangeNotifier {
  static const String _localeKey = 'app_locale';

  Locale _locale = const Locale('zh');
  bool _isLoading = true;

  Locale get locale => _locale;
  bool get isLoading => _isLoading;

  /// 获取当前显示语言名称
  String get languageName {
    switch (_locale.languageCode) {
      case 'zh':
        return '简体中文';
      case 'en':
        return 'English';
      default:
        return '简体中文';
    }
  }

  /// 初始化读取本地保存的语言设置
  Future<void> initialize() async {
    _isLoading = true;
    notifyListeners();

    try {
      final prefs = await SharedPreferences.getInstance();
      final savedLocale = prefs.getString(_localeKey);
      if (savedLocale != null) {
        _locale = Locale(savedLocale);
      }
    } catch (e) {
      debugPrint('加载语言设置失败: $e');
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  /// 切换指定语言
  Future<void> setLocale(Locale locale) async {
    if (_locale == locale) return;
    _locale = locale;

    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(_localeKey, locale.languageCode);
    notifyListeners();
  }

  /// 一键中英文互换
  Future<void> toggleLocale() async {
    if (_locale.languageCode == 'zh') {
      await setLocale(const Locale('en'));
    } else {
      await setLocale(const Locale('zh'));
    }
  }

  /// 获取鸿蒙系统默认语言
  Future<Locale> getSystemLocale() async {
    return WidgetsBinding.instance.platformDispatcher.locale;
  }
}

五、main.dart 全局挂载配置

// main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:mental_health/providers/locale_provider.dart';
import 'package:mental_health/screens/mental_health_home_screen.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 初始化语言配置
  final localeProvider = LocaleProvider();
  await localeProvider.initialize();

  runApp(
    ChangeNotifierProvider.value(
      value: localeProvider,
      child: const MentalHealthApp(),
    ),
  );
}

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

  
  Widget build(BuildContext context) {
    return Consumer<LocaleProvider>(
      builder: (context, localeProvider, child) {
        return MaterialApp(
          title: 'Mental Health',
          debugShowCheckedModeBanner: false,
          // 当前应用语言
          locale: localeProvider.locale,
          // 支持的语言列表
          supportedLocales: const [
            Locale('zh'),
            Locale('en'),
          ],
          // 必加本地化代理,否则文字不生效
          localizationsDelegates: const [
            AppLocalizations.delegate,
            GlobalMaterialLocalizations.delegate,
            GlobalWidgetsLocalizations.delegate,
            GlobalCupertinoLocalizations.delegate,
          ],
          home: const MentalHealthHomeScreen(),
        );
      },
    );
  }
}

六、两种方式使用翻译文本

6.1 官方标准用法(推荐)

import 'package:flutter_gen/gen_l10n/app_localizations.dart';

// 页面中直接使用
Text(AppLocalizations.of(context)!.appTitle)
Text(AppLocalizations.of(context)!.settings)
Text(AppLocalizations.of(context)!.noData)

6.2 自定义工具类翻译(备用方案)

// lib/mental_health/utils/translations.dart
import 'package:flutter/material.dart';

class Translations {
  static String t(BuildContext context, String key) {
    final locale = Localizations.localeOf(context).languageCode;
    return _translations[locale]?[key] ?? key;
  }

  static final Map<String, Map<String, String>> _translations = {
    'zh': {
      'appTitle': '心理健康',
      'moodRecord': '心情记录',
      'meditation': '冥想',
      'quiz': '心理测试',
      'breathing': '呼吸训练',
      'settings': '设置',
    },
    'en': {
      'appTitle': 'Mental Health',
      'moodRecord': 'Mood Record',
      'meditation': 'Meditation',
      'quiz': 'Psychology Test',
      'breathing': 'Breathing Training',
      'settings': 'Settings',
    },
  };
}

调用方式:

Text(Translations.t(context, 'appTitle'))

七、语言设置页面完整代码

// lib/mental_health/screens/language_settings_screen.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:mental_health/providers/locale_provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

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

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(AppLocalizations.of(context)!.language),
      ),
      body: Consumer<LocaleProvider>(
        builder: (context, provider, child) {
          return ListView(
            padding: const EdgeInsets.all(16),
            children: [
              Card(
                elevation: 2,
                shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
                child: Column(
                  children: [
                    ListTile(
                      leading: const Text('🇨🇳', style: TextStyle(fontSize: 24)),
                      title: const Text('简体中文'),
                      trailing: provider.locale.languageCode == 'zh'
                          ? const Icon(Icons.check_circle, color: Colors.green, size: 26)
                          : null,
                      onTap: () => provider.setLocale(const Locale('zh')),
                    ),
                    const Divider(height: 1),
                    ListTile(
                      leading: const Text('🇺🇸', style: TextStyle(fontSize: 24)),
                      title: const Text('English'),
                      trailing: provider.locale.languageCode == 'en'
                          ? const Icon(Icons.check_circle, color: Colors.green, size: 26)
                          : null,
                      onTap: () => provider.setLocale(const Locale('en')),
                    ),
                  ],
                ),
              ),
            ],
          );
        },
      ),
    );
  }
}

八、Flutter for OpenHarmony 鸿蒙专属适配

8.1 获取鸿蒙系统自带语言

// 获取鸿蒙设备系统语言
Future<void> detectSystemLocale() async {
  final systemLocale = WidgetsBinding.instance.platformDispatcher.locale;
  debugPrint('鸿蒙系统当前语言: ${systemLocale.languageCode}');
}

8.2 鸿蒙平台适配注意点

  1. Flutter for OpenHarmony 必须配置 localizationsDelegates 四个代理,少一个会导致切换语言不刷新;
  2. 鸿蒙真机上必须开启 flutter: generate: true 才能正常生成 l10n 代码;
  3. 鸿蒙后台保活情况下,语言切换无需重启 App,Provider 可实时刷新;
  4. 用 SharedPreferences 持久化语言,重启鸿蒙设备、重启 App 都能保留上次语言设置。

九、实战踩坑记录(新手必看)

坑1:arb 文件格式不标准

问题:执行 flutter gen-l10n 报错、生成失败。
解决:arb 文件必须是标准 JSON,不能有注释、不能有多余逗号,键名统一用小驼峰。

坑2:配置了语言但界面不刷新

问题:切换语言后文字不变。
解决:检查 main.dart 是否挂载 AppLocalizations.delegate 和三个全局本地化代理。

坑3:鸿蒙真机无效果,模拟器正常

问题:模拟器多语言正常,鸿蒙真机不生效。
解决:重新执行 flutter cleanflutter pub getflutter gen-l10n 重新编译打包。

坑4:中文翻译乱码

解决:arb 文件保存格式设为 UTF-8,不要用 GBK 编码。


十、大一开发者学习总结

作为计算机大一新生,一开始觉得国际化很高大上、很难上手,实际跟着配置走一遍才发现,Flutter intl + l10n 配置非常规整。

这套方案不仅能在安卓、iOS 用,完全原生适配 Flutter for OpenHarmony 鸿蒙平台,做好多语言之后,App 可以直接适配海外用户、上架鸿蒙应用市场。

掌握这套流程之后,以后所有我的鸿蒙 Flutter 项目都可以直接套用这套模板,开箱即用,不用重复造轮子。

作者:IntMainJhy
创作时间:2026年5月
适配平台:Flutter 全平台 + OpenHarmony 鸿蒙

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐