Flutter 應用國際化 (i18n) 與本地化 (l10n) 完整指南


Flutter 國際化 (i18n) 完全指南:從入門到精通

在現代移動應用開發中,支持多語言是觸達全球用戶的基本要求。Flutter 提供了強大且靈活的國際化 (i18n) 和本地化 (l10n) 支持。本文將帶你從零開始,一步步深入掌握在 Flutter 中實現國際化的幾種主流方法。

目錄

  1. 核心概念
  2. 準備工作:添加依賴
  3. 方法一:使用 flutter_localizations 基礎方案
  4. 方法二:使用 intl 包和 ARB 文件(推薦)
  5. 方法三:使用 easy_localization 第三方庫
  6. 動態切換語言
  7. 處理語言環境相關的數據
  8. 最佳實踐與總結

核心概念

· 國際化 (Internationalization, i18n): 指在應用設計和開發過程中,使其能夠輕松適配不同語言和地區的流程。它是在開發階段完成的。
· 本地化 (Localization, l10n): 指為國際化的應用添加特定語言環境(Locale)的翻譯和格式的過程。它是在國際化之后進行的。
· Locale: 是一個用于標識用戶語言和地區偏好的對象,例如 en-US(美國英語)、zh-CN(簡體中文)、zh-TW(繁體中文)。

Flutter 中的國際化主要涉及:

  1. 為文本(字符串)提供多種語言的翻譯。
  2. 格式化地區相關的數據,如日期、時間、數字和貨幣。
  3. 根據語言環境(如 LTR 或 RTL)調整布局。

準備工作:添加依賴

首先,在你的 pubspec.yaml 文件中添加必要的依賴。我們將使用官方推薦的 intl 包。

dependencies:flutter:sdk: flutterflutter_localizations: # 提供內置組件的本地化資源和基礎類sdk: flutterintl: ^0.18.1 # 用于高級國際化功能,如消息翻譯、日期/數字格式化dev_dependencies:flutter_test:sdk: flutterflutter_lints: ^2.0.0build_runner: ^2.4.0 # 用于生成代碼intl_translation: ^0.9.0 # 用于從 ARB 文件提取和生成本地化代碼

運行 flutter pub get 來安裝這些依賴。

方法一:使用 flutter_localizations 基礎方案

這種方法適用于簡單的應用,手動管理所有字符串。

  1. 配置 MaterialApp/CupertinoApp

在 lib/main.dart 中,配置你的主 Widget 以支持國際化。

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';void main() {runApp(const MyApp());
}class MyApp extends StatelessWidget {const MyApp({super.key});Widget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',// 支持的語言列表supportedLocales: const [Locale('en', ''), // 英語Locale('zh', 'CN'), // 簡體中文Locale('es', ''), // 西班牙語],// 本地化代理,用于加載翻譯和設置特定的本地化功能localizationsDelegates: const [// 提供默認的 Flutter 控件本地化字符串(如按鈕文本)GlobalMaterialLocalizations.delegate,GlobalCupertinoLocalizations.delegate,GlobalWidgetsLocalizations.delegate,// 稍后我們會添加自己的代理// AppLocalizations.delegate,],// 當語言環境不在 supportedLocales 中時,回退到哪個語言localeResolutionCallback: (locale, supportedLocales) {for (var supportedLocale in supportedLocales) {if (supportedLocale.languageCode == locale?.languageCode) {return supportedLocale;}}return supportedLocales.first; // 回退到第一個支持的語言},home: const MyHomePage(),);}
}
  1. 創建自定義本地化類

創建一個文件 lib/l10n/app_localizations.dart。

import 'dart:async';
import 'package:flutter/material.dart';class AppLocalizations {final Locale locale;AppLocalizations(this.locale);static AppLocalizations of(BuildContext context) {return Localizations.of<AppLocalizations>(context, AppLocalizations)!;}static const LocalizationsDelegate<AppLocalizations> delegate =_AppLocalizationsDelegate();// 靜態變量存儲翻譯Mapstatic Map<String, Map<String, String>> _localizedStrings = {'en': {'title': 'Hello World!','message': 'Welcome to my Flutter app.',},'zh_CN': {'title': '你好,世界!','message': '歡迎使用我的 Flutter 應用。',},'es': {'title': '?Hola Mundo!','message': 'Bienvenido a mi aplicación Flutter.',},};// 獲取翻譯的方法String translate(String key) {return _localizedStrings[locale.toString()]![key] ?? '** $key not found **';}// 也可以使用 getter 方法,使代碼更清晰String get title => translate('title');String get message => translate('message');
}// 本地化代理,負責加載具體的本地化資源
class _AppLocalizationsDelegateextends LocalizationsDelegate<AppLocalizations> {const _AppLocalizationsDelegate();bool isSupported(Locale locale) {// 支持的語言列表return ['en', 'zh', 'es'].contains(locale.languageCode);}Future<AppLocalizations> load(Locale locale) async {// 這里通常是異步加載資源的地方(例如從JSON文件)// 我們這個例子是同步的return SynchronousFuture<AppLocalizations>(AppLocalizations(locale));}bool shouldReload(_AppLocalizationsDelegate old) => false;
}
  1. 使用翻譯

在 Widget 中,使用 AppLocalizations.of(context) 來獲取翻譯后的文本。

// lib/pages/my_home_page.dart
import 'package:flutter/material.dart';
import '../l10n/app_localizations.dart';class MyHomePage extends StatelessWidget {const MyHomePage({super.key});Widget build(BuildContext context) {var loc = AppLocalizations.of(context);return Scaffold(appBar: AppBar(title: Text(loc.title), // 使用 getter),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[Text(loc.message), // 使用 getterText(loc.translate('title')), // 或者使用 translate 方法],),),);}
}

優點:簡單直接,無需代碼生成。 缺點:手動管理所有鍵值對,容易出錯,難以維護大量翻譯。

方法二:使用 intl 包和 ARB 文件(推薦)

這是 Google 官方推薦的方法,它使用 .arb (Application Resource Bundle) 文件來管理翻譯,并通過代碼生成來自動創建本地化類。

  1. 項目結構

首先,創建以下目錄結構:

lib/l10n/intl_*.arb          # ARB 翻譯文件app_localizations.dart # 生成的代碼會在這里
  1. 創建 ARB 文件

lib/l10n/intl_en.arb (主資源文件,必須)

{"@@locale": "en","title": "Hello World!","@title": {"description": "The title of the app on the home page"},"message": "Welcome to {appName}","@message": {"description": "A welcome message","placeholders": {"appName": {"type": "String","example": "My Flutter App"}}},"buttonText": "Click Me"
}

lib/l10n/intl_zh_CN.arb

{"@@locale": "zh_CN","title": "你好,世界!","message": "歡迎使用 {appName}","buttonText": "點擊我"
}

lib/l10n/intl_es.arb

{"@@locale": "es","title": "?Hola Mundo!","message": "Bienvenido a {appName}","buttonText": "Haz Clic"
}
  1. 提取和生成代碼

在項目根目錄運行以下命令,從代碼中提取需要翻譯的字符串到 ARB 文件(如果還沒有的話): flutter pub run intl_translation:extract_to_arb --output-dir=lib/l10n lib/l10n/app_localizations.dart

然后,根據 ARB 文件生成 Dart 代碼: flutter pub run intl_translation:generate_from_arb --output-dir=lib/l10n --no-use-deferred-loading lib/l10n/app_localizations.dart lib/l10n/intl_*.arb

這將在 lib/l10n 目錄下生成一系列 messages_*.dart 文件和一個 app_localizations.dart 文件。

  1. 使用生成的代碼

生成的 app_localizations.dart 文件包含了所有邏輯。現在你可以在 Widget 中這樣使用:

import '../l10n/app_localizations.dart';Text(AppLocalizations.of(context)!.title),
Text(AppLocalizations.of(context)!.message('My Awesome App')),
Text(AppLocalizations.of(context)!.buttonText),

優點:翻譯與代碼分離,易于管理和協作(可與翻譯平臺集成);支持帶參數的文本;代碼自動生成,減少錯誤。 缺點:需要設置構建步驟。

方法三:使用 easy_localization 第三方庫

對于追求快速開發和簡單配置的開發者,easy_localization 是一個極佳的選擇。

  1. 添加依賴
dependencies:flutter:sdk: fluttereasy_localization: ^3.0.3dev_dependencies:flutter_test:sdk: flutterbuild_runner: ^2.4.0easy_localization_generator: ^3.0.0 # 用于代碼生成(可選但推薦)
  1. 創建資源文件

在項目根目錄創建 assets/translations 文件夾,并添加 JSON 或 CSV 文件。

assets/translations/en.jsonzh-CN.jsones.json

en.json

{"title": "Hello World!","message": "Welcome to {appName}","buttonText": "Click Me"
}

zh-CN.json

{"title": "你好,世界!","message": "歡迎使用 {appName}","buttonText": "點擊我"
}
  1. 配置 pubspec.yaml

聲明資源文件。

flutter:assets:- assets/translations/
  1. 配置 Main App
import 'package:easy_localization/easy_localization.dart';void main() async {WidgetsFlutterBinding.ensureInitialized(); // 需要先初始化await EasyLocalization.ensureInitialized(); // 初始化 EasyLocalizationrunApp(EasyLocalization(supportedLocales: const [Locale('en'), Locale('zh', 'CN'), Locale('es')],path: 'assets/translations', // 資源文件路徑fallbackLocale: const Locale('en'), // 回退語言child: const MyApp(), // 你的應用),);
}class MyApp extends StatelessWidget {const MyApp({super.key});Widget build(BuildContext context) {return MaterialApp(localizationsDelegates: context.localizationDelegates,supportedLocales: context.supportedLocales,locale: context.locale,home: const MyHomePage(),);}
}
  1. 使用翻譯
Text('title'.tr()), // 簡單文本
Text('message'.tr(args: ['My App'])), // 帶參數的文本
// 或者使用生成代碼(如果用了 easy_localization_generator)
Text(LocaleKeys.title.tr()),

優點:設置簡單,API 非常簡潔,功能強大(支持復數、性別等)。 缺點:依賴第三方庫。

動態切換語言

無論使用哪種方法,動態切換語言的邏輯是相似的。通常使用 Provider 或 Riverpod 來管理狀態。

// 一個簡單的 Provider 例子
import 'package:flutter/material.dart';class LocaleProvider with ChangeNotifier {Locale? _locale;Locale? get locale => _locale;void setLocale(Locale newLocale) {_locale = newLocale;notifyListeners();}void clearLocale() {_locale = null;notifyListeners();}
}// 在 MaterialApp 中使用
return MaterialApp(locale: context.watch<LocaleProvider>().locale, // 來自 Provider...
);// 在設置頁面切換語言
ListTile(title: Text('English'),onTap: () {context.read<LocaleProvider>().setLocale(Locale('en'));Navigator.pop(context);},
),
ListTile(title: Text('簡體中文'),onTap: () {context.read<LocaleProvider>().setLocale(Locale('zh', 'CN'));Navigator.pop(context);},
),

處理語言環境相關的數據

使用 intl 包來格式化數據。

import 'package:intl/intl.dart';String formatDate(DateTime date, BuildContext context) {return DateFormat.yMMMMd( Localizations.localeOf(context).toString() ).format(date);
}String formatCurrency(double amount, BuildContext context) {return NumberFormat.currency(locale: Localizations.localeOf(context).toString(),symbol: '' // 可能需要根據貨幣調整).format(amount);
}// 在 Widget 中使用
Text( formatDate(DateTime.now(), context) ),
Text( formatCurrency(29.99, context) ),

最佳實踐與總結

  1. 選擇合適的方法:
    · 小型項目/原型:easy_localization 最快。
    · 中大型項目/團隊協作:官方 intl + ARB 文件最規范,易于維護。
    · 簡單演示:手動管理 Map 也可以。
  2. 鍵名要有意義:使用類似 homePageWelcomeMessage 的鍵名,而不是 msg1。
  3. 提供上下文描述:在 ARB 文件中使用 @key 的 description 字段,幫助翻譯者理解上下文。
  4. 處理文本方向:注意 RTL (Right-to-Left) 語言(如阿拉伯語、希伯來語)的布局適配。Directionality Widget 可以幫你。
  5. 不要拼接字符串:類似 ‘Hello ’ + name 的拼接在其他語言中語序可能不同,務必使用帶參數的翻譯。
  6. 測試:務必在不同語言環境下測試你的應用,檢查布局是否錯亂,翻譯是否完整。

總結:Flutter 提供了從簡單到復雜的多種國際化方案。intl + ARB 的組合是官方推薦的“黃金標準”,平衡了功能性和可維護性。而 easy_localization 則為開發者提供了快速實現的捷徑。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/98834.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/98834.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/98834.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

計算機視覺與深度學習 | 計算機視覺中線特征提取與匹配算法綜述

文章目錄 一、線特征提取算法原理 1.1 Hough變換及其優化 1.2 LSD算法 1.3 EDLines算法 二、核心數學公式 2.1 直線表示與誤差計算 2.2 LSD算法關鍵公式 三、線特征匹配算法 3.1 LBD描述符 3.2 匹配策略 四、代碼實現 4.1 LSD線段檢測(Python) 4.2 LBD特征匹配(C++) 五、算…

Transformer 模型:Attention is All You Need 的真正含義

2017 年&#xff0c;Google Brain 發布了一篇具有里程碑意義的論文——《Attention Is All You Need》&#xff0c;這篇論文不僅首次提出了 Transformer 模型&#xff0c;更重要的是&#xff0c;它宣稱“注意機制&#xff08;Attention Mechanism&#xff09;就足以構建強大的模…

數據庫約束表的設計

數據庫約束概念&#xff1a;數據庫約束是關系型數據庫的一個重要功能&#xff0c;主要是保證數據的完整性&#xff0c;也可理解為數據的正確性&#xff08;數據本身是否正確&#xff0c;關聯關系是否正確&#xff09;&#xff08;一般是用在指定列上&#xff09;常見的約束類型…

【案例分享】TeeChart 助力 Softdrill 提升油氣鉆井數據可視化能力

在鉆井與地質工程領域&#xff0c;數據可視化是核心環節。圖表不僅需要精確與高效&#xff0c;還需符合行業習慣并支持交互與定制。Softdrill 自 2012 年起在核心產品中集成了TeeChart 圖表庫&#xff0c;將復雜的井下數據轉化為直觀的工程圖表&#xff0c;極大提升了鉆井工程師…

【Flink】Flink Runtime 架構設計

Flink Runtime 架構設計 整體架構 ┌─────────────────────────────────────────────────────────────────┐ │ Flink Runtime │ ├─────────…

Git 命令教程

Git介紹 分布式版本控制系統。 Git命令 初始化/全局配置git init初始化一個Git倉庫&#xff08;會創建一個.git的目錄&#xff09;git config --global user.name “name”設置提交時的用戶名git config user.name查看設置的用戶名git config --global user.email “youemail.c…

git config --global user.name指令報錯時的解決方案

問題分析 %HOMEDRIVE%%HOMEPATH%/.gitconfig 是Windows環境變量的表示方式&#xff1a; %HOMEDRIVE% 通常是 C:%HOMEPATH% 通常是 \Users\你的用戶名完整路徑應該是&#xff1a;C:\Users\你的用戶名\.gitconfig 但這里環境變量沒有被正確解析&#xff0c;顯示的是字面意思。 …

websocket和socket io的區別

好的&#xff0c;這是一個更具體也更常見的問題。WebSocket 是一種協議&#xff0c;而 Socket.IO 是一個庫&#xff0c;它使用了 WebSocket 但提供了多得多的功能。 簡單比喻&#xff1a; WebSocket 就像是給你提供了一條高效的“快遞專線”&#xff08;雙向通信通道&#xff…

Nginx反向代理與負載均衡部署

Nginx反向代理與負載均衡部署實戰指南前言一、規劃部署負載均衡和反向代理二、部署Nginx負載均衡器2.1. 準備基礎環境2.2. 創建Nginx運行用戶2.3. 編譯安裝Nginx2.4. 配置Nginx系統服務2.5. 驗證Nginx安裝三、部署后端2臺Tomcat應用服務器3.1. 安裝JDK3.2. 部署Tomcat實例13.3.…

從源碼和設計模式深挖AQS(AbstractQueuedSynchronizer)

AQS 概念 AbstractQueuedSynchronizer&#xff08;AQS&#xff09; 是 Java 并發包 (java.util.concurrent.locks) 的核心基礎框架&#xff0c;它的實現關鍵是先進先出 (FIFO) 等待隊列和一個用volatile修飾的鎖狀態status。具體實現有 : ReentrantLock、Semaphore、CountDownL…

Dart → `.exe`:Flutter 桌面與純命令行雙軌編譯完全指南

Dart → .exe&#xff1a;Flutter 桌面與純命令行雙軌編譯完全指南 關鍵詞&#xff1a;Dart、Flutter、Windows、可執行文件、桌面端、CLI、交叉編譯 1. 前言 很多開發者以為 Dart 只能跑在 AOT 移動端或 Web 端&#xff0c;其實 官方工具鏈早已支持一鍵輸出 Windows 原生 .ex…

互聯網接入網中PPPoE和PPP協議

<摘要> PPPoE和PPP是寬帶接入網絡中至關重要的協議組合&#xff0c;其中PPP提供通用的點對點鏈路層解決方案&#xff0c;而PPPoE則是在以太網架構上擴展PPP應用的技術橋梁。本文從技術演進視角系統解析了兩者的內在關聯與本質區別&#xff1a;PPP作為成熟鏈路層協議&…

詳細解析SparkStreaming和Kafka集成的兩種方式的區別和優劣

spark streaming是基于微批處理的流式計算引擎&#xff0c;通常是利用spark core或者spark core與spark sql一起來處理數據。在企業實時處理架構中&#xff0c;通常將spark streaming和kafka集成作為整個大數據處理架構的核心環節之一。 針對不同的spark、kafka版本&#xff0…

Kite Compositor for Mac v2.1.2 安裝教程|DMG文件安裝步驟(Mac用戶必看)

Kite Compositor? 是一款專為 ?macOS? 設計的 ?輕量級界面設計 & 動畫制作工具&#xff0c;它可以讓你像拼圖一樣直觀地 ?創建、編輯和預覽用戶界面&#xff08;UI&#xff09;以及動畫效果。 一、下載文件 首先&#xff0c;你得先把這個 ?Kite Compositor for Mac …

【逆向】Android程序靜態+動態分析——去殼

對提供的 CrackmeTest.apk 進行逆向分析&#xff0c;程序含有反調試機制&#xff08;加殼&#xff09;&#xff0c;通過靜態補丁反反調試&#xff08;去殼&#xff09;&#xff0c;再動態調試獲取其中密碼。 目錄 環境 基礎 實驗內容 靜態分析 動態分析 反反調試 再動態…

Rust 開發環境安裝與 crates.io 國內源配置(Windows / macOS / Linux 全流程)

Rust 這幾年在系統編程、WebAssembly、區塊鏈、后端服務領域越來越火&#xff0c;很多開發者都在嘗試用它做一些新項目。 但是國內安裝 Rust 開發環境時&#xff0c;經常遇到 安裝慢、依賴拉不下來、crates.io 超時 等問題。本文結合個人踩坑經驗&#xff0c;整理了一份 跨平臺…

Nginx SSL/TLS 配置

Nginx SSL/TLS 配置指南&#xff1a;從入門到安全強化前言一、環境準備&#xff1a;Nginx安裝配置1.1. **EPEL倉庫配置**&#xff1a;1.2. **Nginx安裝**&#xff1a;1.3. **服務啟停管理**&#xff1a;1.4. **服務狀態驗證**&#xff1a;二、SSL/TLS證書獲取方案方案A&#xf…

Java ReentrantLock和synchronized的相同點與區別

1. 核心概念與定位synchronized&#xff1a;Java 內置的關鍵字&#xff0c;屬于 JVM 層面的隱式鎖。通過在方法或代碼塊上聲明&#xff0c;自動實現鎖的獲取與釋放&#xff0c;無需手動操作。設計目標是提供簡單易用的基礎同步能力&#xff0c;適合大多數常規同步場景。Reentra…

【npm】npm 包更新工具 npm-check-updates (ncu)

npm 包太多了&#xff0c;一個項目有那么多依賴包&#xff0c;它們的升級管理需要一個工具&#xff1a;npm-check-updates&#xff1a; 安裝&#xff1a; npm install -g npm-check-updates安裝之后&#xff0c;就可以使用它的命令&#xff1a;ncu 查看哪些包可以升級&#xff…

go資深之路筆記(一) Context

一、 Context 的正確使用與底層原理 1.結構體 type Context interface {// Deadline 返回此 Context 被取消的時間點。// 如果未設置截止時間&#xff0c;ok 為 false。Deadline() (deadline time.Time, ok bool)// Done 返回一個 channel。當 Context 被取消或超時后&#xff…