GetX:多语言

入门案例

代码

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 只写了英文,就不会出现缺失文本的情况。

TranslationsLocale(...)

Localed 的两个参数:Locale(String languageCode, [String? countryCode])

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) 对应Translationskeys 的 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

.trGetX 为 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 对象)。

languageCodeLocale 的第一个参数,表示语言,比如 'en''zh'

?. 是 Dart 的空安全操作符,防止 locale 为 null。

Get.updateLocale(Locale('zh', 'CN'))

  • 作用:动态更新应用语言。
  • Locale('zh', 'CN') 是 Flutter 内置类,表示中文简体。
  • 调用后:
    1. GetX 会把当前语言更新为这个 Locale
    2. 全局所有使用 .tr 的文本都会自动刷新 UI
    3. 不需要刷新页面,GetX 会 自动触发界面重建

多语言介绍

一个静态文本映射系统

GetX 的多语言功能 并不是自动翻译(AI 翻译或 Google Translate 风格的实时翻译),它本质上是 一个静态文本映射系统,更像是 “关键位置的语言配置”。

它需要手动定义文本映射,为每个 key 写好各语言对应的翻译。

'login': '登录', // zh_CN
'login': 'Login', // en_US

适合按钮文字、提示信息、标题、标签等界面结构性文字。但是不适合动态内容或长文本自动翻译。

优点

  • 简单、轻量、零依赖
  • 切换语言时界面自动刷新
  • 可配合 trParams 处理简单动态参数(如 Hello @nameHello Tom

局限性

  • 大量文本需要手动维护
  • 不能自动识别语言环境里的新内容
  • 多语言扩展到上百条时,需要额外管理机制(如 JSON 或 CSV 文件)
使用场景类型 是否适合 GetX 多语言 说明
按钮文字 静态、结构性文本,易于维护
菜单、Tab、导航栏标题 界面固定元素,可通过 key 快速映射
提示信息 / 弹窗 提示语、验证信息等短文本适合手动翻译
App 内部固定标签 如“用户名”、“密码”、“设置”等
表格列名 / 表单标签 固定字段文本可直接定义
用户生成内容 / 评论 动态内容无法通过静态 key 映射,需要调用自动翻译服务
长篇文章 / 新闻内容 静态映射不适合大量文本,维护成本高
外部 API 返回内容 需要实时翻译或多语言处理,需要额外接口
动态生成文本 ❌ / ⚠️ 可以用 trParams 处理简单参数替换,但复杂动态文本不适合

i18n

i18ninternationalization(国际化) 的缩写。因为这个单词太长了,工程师们取了个简写:

  • 首字母 i
  • 最后一个字母 n
  • 中间有 18 个字母
  • 于是就叫 i18n

类似的还有:

  • l10n = localization(本地化,本地适配),中间有 10 个字母。
  • g11n = globalization(全球化)。

在软件开发里,**i18n(国际化)**指的是:在不修改代码逻辑的前提下,让程序能够支持多种语言、文化习惯和地区差异。比如:

  • 文本:同一按钮在中文显示“登录”,在英文显示“Login”。
  • 数字/货币格式1,234.56(美国) vs 1.234,56(德国)。
  • 日期格式2025-08-25(中国) vs 08/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。所以如果你只翻译自己界面上的文本(hellowelcome 等),没有问题。

用到系统内置组件就必须用localizationsDelegates

  • 当你用到 Flutter SDK 内置的组件(比如 showDatePickerTimePickerAlertDialog 的 “取消/确定” 按钮),这些文案来自系统,而不是你的 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)

  1. PlatformDispatcher
    • Flutter 框架中负责和底层平台交互的类(相当于和操作系统沟通的“调度器”)。
    • 其中包含了屏幕信息、系统字体缩放、语言环境、UI主题等和平台相关的全局信息。
  2. PlatformDispatcher.instance
    • 这是一个 单例对象,代表当前 Flutter 引擎对应的 PlatformDispatcher
    • 所有和平台交互的信息都能从这里取到。
  3. .locale
    • 返回当前平台(操作系统)的 语言环境设置Locale 对象)。
    • 例如:
      • 如果系统是中文(简体),则可能返回:Locale("zh", "CN")
      • 如果系统是英文(美国),则可能返回:Locale("en", "US")

×

喜欢就点赞,疼爱就打赏