入门案例
代码
import 'package:flutter/material.dart';
import 'package:get/get.dart';
// ------------------------ 1.创建语言类 ------------------------------
class MyTranslations extends Translations {
@override
Map<String, Map<String, String>> get keys => {
'en_US': {'hello': 'Hello', 'welcome': 'Welcome to GetX'},
'zh_CN': {'hello': '你好', 'welcome': '欢迎使用 GetX'},
};
}
// -------------------------- 2.在 GetMaterialApp 中注册 --------------------
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'GetX i18n Demo',
translations: MyTranslations(), // 注册翻译类
locale: const Locale('zh', 'CN'), // 默认语言
fallbackLocale: const Locale('en', 'US'), // 兜底语言
// 支持的语言种类
supportedLocales: [
Locale('en'), // 英文
Locale('zh'), // 中文
],
home: const HomePage(),
);
}
}
// -------------------------- 3.在界面中使用 tr 获取翻译文本 --------------------------
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('hello'.tr)),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('welcome'.tr),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// 切换语言
if (Get.locale?.languageCode == 'zh') {
Get.updateLocale(const Locale('en', 'US'));
} else {
Get.updateLocale(const Locale('zh', 'CN'));
}
},
child: Text('切换语言 / Switch Language'),
),
],
),
),
);
}
}
代码讲解
translations: MyTranslations()
- 作用:告诉 GetX 你的多语言资源在哪里。
- 类型:必须是继承自
Translations的类实例。 - 原理:GetX 会根据当前语言
locale从这个类里读取 key → 文本映射。
这里 MyTranslations 里有所有的语言映射:
'en_US': {'hello': 'Hello'},
'zh_CN': {'hello': '你好'},
当你在界面上写 'hello'.tr 时,GetX 会自动根据当前 locale 去查找对应的文本。
locale: const Locale('zh', 'CN')
如果你不写
locale,那么默认是 跟随系统语言(即用手机或者电脑的Locale)。作用:设置应用的默认语言环境。
类型:
Locale类的实例。当 App 启动时,GetX 会用这个语言作为初始语言。
如果用户切换语言,可以调用:
Get.updateLocale(Locale('en', 'US'));
fallbackLocale: const Locale('en', 'US')
作用:兜底语言,当当前 locale 没有对应 key 时使用。
为什么需要:
- 假设
'welcome'在zh_CN里不存在,但在en_US里有。 - 使用
fallbackLocale后,GetX 会自动使用'en_US'的值,而不是报错或显示空字符串。
也就是当你的 app 支持中文和英文,但某些 key 只写了英文,就不会出现缺失文本的情况。
Translations和Locale(...)
Localed 的两个参数:Locale(String languageCode, [String? countryCode])
languageCode→ 外层 Map 的第一部分countryCode→ 外层 Map 的第二部分(可选)
class MyTranslations extends Translations {
@override
Map<String, Map<String, String>> get keys => {
'en_US': {'hello': 'Hello', 'welcome': 'Welcome to GetX'},
'zh_CN': {'hello': '你好', 'welcome': '欢迎使用 GetX'},
};
}
Locale(languageCode, countryCode) 对应Translations的 keys 的 key,否则找不到文本就会用 fallbackLocale
但是不是固定的,可以自定义。比如:
| 外层 key(keys) | Locale 对应方式 |
|---|---|
| ‘en_US’ | Locale(‘en’, ‘US’) |
| ‘zh_CN’ | Locale(‘zh’, ‘CN’) |
| ‘aa_bb’ | Locale(‘aa’, ‘bb’) |
| ‘cc_dd’ | Locale(‘cc’, ‘dd’) |
'xxxx'.tr
.tr 是 GetX 为 String 扩展的一个 getter,用来从当前语言映射表中取值。它不是 Dart 自带的属性,而是 GetX 扩展了 String 类。
// 以下是简化版的源码
extension Trans on String {
String get tr {
// 获取当前语言 locale
Locale locale = Get.locale ?? Get.fallbackLocale ?? Locale('en', 'US');
// 拼接 key(locale.languageCode + _ + countryCode)
String langKey = '${locale.languageCode}_${locale.countryCode}';
// 从 translations 中找对应文本
return Get.translations?[langKey]?[this] ?? this;
}
}
所以 'hello'.tr 的意思就是:“取当前语言环境下 key 为 'hello' 的翻译,如果找不到就返回原字符串。”
Get.locale?.languageCode
Get.locale 返回当前 应用语言环境(一个 Locale 对象)。
languageCode 是 Locale 的第一个参数,表示语言,比如 'en'、'zh'。
?. 是 Dart 的空安全操作符,防止 locale 为 null。
Get.updateLocale(Locale('zh', 'CN'))
- 作用:动态更新应用语言。
Locale('zh', 'CN')是 Flutter 内置类,表示中文简体。- 调用后:
- GetX 会把当前语言更新为这个
Locale - 全局所有使用
.tr的文本都会自动刷新 UI - 不需要刷新页面,GetX 会 自动触发界面重建。
- GetX 会把当前语言更新为这个
多语言介绍
一个静态文本映射系统
GetX 的多语言功能 并不是自动翻译(AI 翻译或 Google Translate 风格的实时翻译),它本质上是 一个静态文本映射系统,更像是 “关键位置的语言配置”。
它需要手动定义文本映射,为每个 key 写好各语言对应的翻译。
'login': '登录', // zh_CN
'login': 'Login', // en_US
适合按钮文字、提示信息、标题、标签等界面结构性文字。但是不适合动态内容或长文本自动翻译。
优点
- 简单、轻量、零依赖
- 切换语言时界面自动刷新
- 可配合
trParams处理简单动态参数(如Hello @name→Hello Tom)
局限性
- 大量文本需要手动维护
- 不能自动识别语言环境里的新内容
- 多语言扩展到上百条时,需要额外管理机制(如 JSON 或 CSV 文件)
| 使用场景类型 | 是否适合 GetX 多语言 | 说明 |
|---|---|---|
| 按钮文字 | ✅ | 静态、结构性文本,易于维护 |
| 菜单、Tab、导航栏标题 | ✅ | 界面固定元素,可通过 key 快速映射 |
| 提示信息 / 弹窗 | ✅ | 提示语、验证信息等短文本适合手动翻译 |
| App 内部固定标签 | ✅ | 如“用户名”、“密码”、“设置”等 |
| 表格列名 / 表单标签 | ✅ | 固定字段文本可直接定义 |
| 用户生成内容 / 评论 | ❌ | 动态内容无法通过静态 key 映射,需要调用自动翻译服务 |
| 长篇文章 / 新闻内容 | ❌ | 静态映射不适合大量文本,维护成本高 |
| 外部 API 返回内容 | ❌ | 需要实时翻译或多语言处理,需要额外接口 |
| 动态生成文本 | ❌ / ⚠️ | 可以用 trParams 处理简单参数替换,但复杂动态文本不适合 |
i18n
i18n 是 internationalization(国际化) 的缩写。因为这个单词太长了,工程师们取了个简写:
- 首字母 i
- 最后一个字母 n
- 中间有 18 个字母
- 于是就叫 i18n。
类似的还有:
- l10n = localization(本地化,本地适配),中间有 10 个字母。
- g11n = globalization(全球化)。
在软件开发里,**i18n(国际化)**指的是:在不修改代码逻辑的前提下,让程序能够支持多种语言、文化习惯和地区差异。比如:
- 文本:同一按钮在中文显示“登录”,在英文显示“Login”。
- 数字/货币格式:
1,234.56(美国) vs1.234,56(德国)。 - 日期格式:
2025-08-25(中国) vs08/25/2025(美国)。 - 文字方向:英文/中文是 LTR(从左到右),阿拉伯语/希伯来语是 RTL(从右到左)。
.trParams
import 'package:flutter/material.dart';
import 'package:get/get.dart';
// ------------------------ 1.创建语言类 ------------------------------
class MyTranslations extends Translations {
@override
Map<String, Map<String, String>> get keys => {
// 在翻译表里写占位符(用 @参数名 标识)
'en_US': {
'hello': 'Hello @name',
'welcome': 'Welcome to GetX, @name. You are @age years old.',
},
'zh_CN': {'hello': '你好,@name', 'welcome': '欢迎使用 GetX,@name。今年 @age 岁。'},
};
}
// -------------------------- 2.在 GetMaterialApp 中注册 --------------------
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'GetX i18n Demo',
translations: MyTranslations(), // 注册翻译类
locale: const Locale('zh', 'CN'), // 默认语言
fallbackLocale: const Locale('en', 'US'), // 兜底语言
home: const HomePage(),
);
}
}
// -------------------------- 3.在界面中使用 trParams 获取翻译文本 --------------------------
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
// 代码中调用 .trParams({}) 传递参数:
appBar: AppBar(title: Text('hello'.trParams({'name': 'Tom'}))), // 单参数
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 多参数: 是根据名字来传递的,和位置无关
Text('welcome'.trParams({'name': 'Alice', 'age': '20'})),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// 切换语言
if (Get.locale?.languageCode == 'zh') {
Get.updateLocale(const Locale('en', 'US'));
} else {
Get.updateLocale(const Locale('zh', 'CN'));
}
},
child: Text('切换语言 / Switch Language'),
),
],
),
),
);
}
}
localizationsDelegates
是什么
在 Flutter 多语言配置里,localizationsDelegates 是一个 代理列表,告诉 Flutter 去哪里加载不同语言的资源(比如文本翻译、日期/时间/货币格式、左右排版等)。
换句话说,它是 Flutter 国际化“资源工厂”。
一般情况下,会看到这样的配置:
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate, // Material 组件多语言
GlobalWidgetsLocalizations.delegate, // 基础Widget多语言
GlobalCupertinoLocalizations.delegate, // Cupertino风格多语言
],
这些代理帮你处理:
- ✅ 系统自带的 UI 文本翻译(如对话框里的 “OK” / “取消” / “复制”)。
- ✅ 日期、时间、货币、数字格式。
- ✅ 文字排版方向(LTR/RTL)。
translations与localizationsDelegates
localizationsDelegates不是必须的,没有localizationsDelegates程序也可以运行。
只用 GetX 的 translations 就可以不写 localizationsDelegates,不会报错。
GetX 的
translations本身不依赖 Flutter 的内置本地化系统。只要你调用
Text('xxx'.tr),GetX 就会去你的MyTranslations词典里找对应翻译,不需要依赖GlobalMaterialLocalizations。所以如果你只翻译自己界面上的文本(hello、welcome等),没有问题。
用到系统内置组件就必须用localizationsDelegates
- 当你用到 Flutter SDK 内置的组件(比如
showDatePicker、TimePicker、AlertDialog的 “取消/确定” 按钮),这些文案来自系统,而不是你的translations。 - 如果没有加
localizationsDelegates,它们就会始终显示英文(”Cancel” / “OK”),不会自动切换成中文。
案例
flutter_localizations
在使用多语言前,要确保有这个依赖。
dependencies:
flutter_localizations:
sdk: flutter
- 旧版本 Flutter(2.x、3.0 以前)
pubspec.yaml里通常 不会默认带flutter_localizations,如果要用多语言,需要手动加。 - **新版本 Flutter(3.7+ / 3.10+)**默认创建的项目里 已经带上了
flutter_localizations
flutter_localizations:是 Flutter 官方提供的 本地化支持库,里面包含了各种语言环境的翻译、格式化工具(日期、货币、方向 LTR/RTL 等)。如果要在 App 里支持多语言(国际化 i18n),通常需要用到它。它提供一批现成的 LocalizationsDelegate,用来支持 Flutter 自带的组件(Material、Cupertino、Widget 层)的多语言。但是与Getx的translations无关。
代码
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:get/get.dart';
class MyTranslations extends Translations {
@override
Map<String, Map<String, String>> get keys => {
'en_US': {'hello': 'Hello', 'welcome': 'Welcome to GetX'},
'zh_CN': {'hello': '你好', 'welcome': '欢迎使用 GetX'},
'zh_HK': {'hello': '你好(香港)', 'welcome': '歡迎使用 GetX'},
};
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'i18n Demo',
translations: MyTranslations(),
// 配置多语言支持
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
// 这里的Locale 用的是flutter_localizations的翻译器
locale: const Locale('zh', 'HK'), // 默认语言
supportedLocales: const [
Locale('en', 'US'), // 英文
Locale('zh', 'CN'), // 中文
Locale('zh', 'HK'), // 中文香港
],
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("i18n Demo")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 情况 A:手动写死的按钮文本
Text("${"hello".tr} - ${"welcome".tr}"),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
showDialog(
context: context,
builder: (_) => AlertDialog(
title: const Text("手动写死文本"),
actions: [
TextButton(
onPressed: () {},
child: const Text("取消"),
), // 不会自动翻译
TextButton(
onPressed: () {},
child: const Text("确定"),
), // 不会自动翻译
],
),
);
},
child: const Text("手动写死按钮"),
),
const SizedBox(height: 20),
// 情况 B:系统自带的翻译(DatePicker)
ElevatedButton(
onPressed: () {
// 在这里,我们没有用到 GetX 的翻译功能,
// 而是直接使用了 Flutter 的本地化支持
showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2000),
lastDate: DateTime(2100),
);
},
child: const Text("系统内置翻译按钮 (DatePicker)"),
),
],
),
),
);
}
}
效果如下,我们可以看到,系统默认使用的是繁体中文,如果在代码里面写死,就会直接显示写死的内容。
如果我们使用了内置的组件,如showDatePicker,里面是没有使用我们定制的翻译词典,会用自己自带的,也可以翻译,这个时候我们必须指定localizationsDelegates。
supportedLocales
它表示 你的 App 支持的语言列表,也就是用户能切换的语言范围。
- 类型是:
List<Locale> - 每个
Locale包含两个参数:- 语言代码(如
"en"= English,"zh"= 中文) - 国家/地区代码(可选,如
"US"、"CN")
- 语言代码(如
supportedLocales: const [
Locale('en', 'US'), // 英文
Locale('zh', 'CN'), // 中文
Locale('zh', 'HK'), // 中文香港
],
使用了supportedLocales一定要使用localizationsDelegates,否则会报错
A MaterialLocalizations delegate that supports the zh_CN locale was not found. A CupertinoLocalizations delegate that supports the zh_CN locale was not found.因为Flutter 在构建
AppLocalizations时会走一条逻辑:
- 它会从
supportedLocales拿出所有候选 Locale- 决定当前应用该用哪个(匹配系统语言,或者你指定的
locale)- 然后:调用
localizationsDelegates去加载该 Locale 的资源- 所以有
supportedLocales但没写localizationsDelegates: 遍历时发现没有 delegate → 所有 Locale 都找不到翻译 → 报错- 有
localizationsDelegates但是没有supportedLocales: Flutter 根本不走这段匹配逻辑(直接默认英文)。
如果 只写了 localizationsDelegates,没写 supportedLocales:Flutter 能加载翻译资源,但它不知道你支持哪些语言 → 可能直接用系统默认语言,或者 fallback 到英文。
一个标准的多语言配置
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'GetX i18n Demo',
// GetX 翻译配置
translations: MyTranslations(),
locale: const Locale('zh', 'CN'), // 默认语言
fallbackLocale: const Locale('en', 'US'), // 兜底语言
// Flutter 官方多语言支持
supportedLocales: const [
Locale('en', 'US'), // 英文
Locale('zh', 'CN'), // 中文
],
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
home: const HomePage(),
);
}
}
一个获取系统语言的方法
Locale locale = PlatformDispatcher.instance.locale;
主要作用是 获取当前系统的默认语言环境(Locale)。
PlatformDispatcher- Flutter 框架中负责和底层平台交互的类(相当于和操作系统沟通的“调度器”)。
- 其中包含了屏幕信息、系统字体缩放、语言环境、UI主题等和平台相关的全局信息。
PlatformDispatcher.instance- 这是一个 单例对象,代表当前 Flutter 引擎对应的
PlatformDispatcher。 - 所有和平台交互的信息都能从这里取到。
- 这是一个 单例对象,代表当前 Flutter 引擎对应的
.locale- 返回当前平台(操作系统)的 语言环境设置(
Locale对象)。 - 例如:
- 如果系统是中文(简体),则可能返回:
Locale("zh", "CN") - 如果系统是英文(美国),则可能返回:
Locale("en", "US")
- 如果系统是中文(简体),则可能返回:
- 返回当前平台(操作系统)的 语言环境设置(