【Flutter】多语言方案一:flutter_localizations 与 GetX 配合版

介绍

多语言方案:flutter_localizations 与 GetX 配合版,好处:命令行生成多语言字符串的引用常量类,缺点:切换语言以后,主界面需要手动触发setState,重绘将最新的Locale数据设置给GetMaterialApp。



运行效果

在这里插入图片描述

一、安装

dependencies:
flutter_localizations:
sdk: flutter
intl: any
get: ^4.6.6

flutter:
uses-material-design: true
generate: true

二、使用

1.lib文件夹中新建文件夹l10n/arb,并在其中创建app_en.arb 、app_zh.arb、app_zh_HK.arb文件

app_en.arb类

{
  "@@locale": "en",
  "appName": "BraveComponent",
  "@appName": {
      "description": "备注"
  },
  "helloWorld": "HelloWorld",
  "followerSystemLanguage": "FollowerSystemLanguage",
  "simplifiedChinese": "SimplifiedChinese",
  "traditionalChinese": "TraditionalChinese",
  "english": "English",
  "setting": "Setting",
  "multiLanguage": "MultiLanguage",
  "theme": "Theme"
}

app_zh.arb类

{
  "@@locale": "zh",
  "appName": "BraveComponent",
  "@appName": {
      "description": "备注"
  },
  "helloWorld": "你好,世界",
  "followerSystemLanguage": "跟随系统语言",
  "simplifiedChinese": "简体中文",
  "traditionalChinese": "繁体中文",
  "english": "英文",
  "setting": "设置",
  "multiLanguage": "多语言",
  "theme": "主题"
}

app_zh.arb类

{
   "@@locale": "zh_HK",
   "appName": "BraveComponent",
   "@appName": {
       "description": "備注"
   },
   "helloWorld": "妳好,世界",
   "followerSystemLanguage": "跟隨系統語言",
   "simplifiedChinese": "簡體中文",
   "traditionalChinese": "繁體中文",
   "english": "英文",
   "setting": "設置",
   "multiLanguage": "多語言",
   "theme": "主題"
}

2.项目的根目录中添加l10n.yaml,配置如下

arb-dir: lib/l10n/arb
template-arb-file: app_zh.arb
output-localization-file: app_localizations.dart
output-class: AppLocalizations
use-deferred-loading: true
nullable-getter: false

3.添加完成之后,执行命令flutter gen-l10n,执行命令flutter run,.dart_tools会自动生成相关的文件

在这里插入图片描述

4.MaterialApp改成GetMaterialApp配置国际化字段

l10n_app.dart类代码

import 'package:brave_component/core/utils/language_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:get/get.dart';

import 'l10n/l10n.dart';
import 'routes/route_pages.dart';
import 'routes/route_path.dart';

class L10nApp extends StatefulWidget {
  bool _init = true;
  L10nApp({super.key});

  @override
  State<L10nApp> createState() => L10nAppState();
}

class L10nAppState extends State<L10nApp> {
  // 供外部使用的_AppSetting实例,用于修改app的状态
  static AppSetting setting = AppSetting.instance;

  @override
  void initState() {
    super.initState();

    //第一次进入app时,获取本地多语言的countryCode
    if (widget._init) {
      setting.setLocale();
      widget._init = false;
    }
    // 更改语言
    setting.changeLocale = () {
      setState(() {});
    };
  }

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      initialRoute: RoutePath.l10n_main,
      getPages: RoutePages.getPages,
      title: 'component',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      locale: setting._locale,
      fallbackLocale: const Locale("zh", "CN"),
      localeResolutionCallback: (deviceLocale, supportedLocales) {
        print('当前语言:${deviceLocale.toString()}');
        return;
      },
      supportedLocales: AppLocalizations.supportedLocales,
      localizationsDelegates: const [
        AppLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalMaterialLocalizations.delegate
      ],
    );
  }
}

class AppSetting {
  AppSetting._();

  static final AppSetting _instance = AppSetting._();

  static AppSetting get instance => _instance;
  Locale? _locale;

  Function()? changeLocale;

  void setLocale() {
    _locale = LanguageUtils.getLocale();
  }
}

language_utils.dart类代码

import 'package:brave_component/l10n/l10n.dart';
import 'package:flutter/widgets.dart';
import 'package:get/get.dart';

import '../../l10n_app.dart';
import '../cache/helpers/cache_helper.dart';
import '../enums/language.dart';

class LanguageUtils {
  static String getLanguage(BuildContext context, String code) {
    late String language;
    switch (code) {
      case 'fs-Lan':
        language = context.l10n.followerSystemLanguage;
        break;
      case 'zh-CN':
        language = context.l10n.simplifiedChinese;
        break;
      case 'zh-HK':
        language = context.l10n.traditionalChinese;
        break;
      case 'en-US':
        language = context.l10n.english;
        break;
      default:
        language = context.l10n.followerSystemLanguage;
        break;
    }
    return language;
  }

  static Locale? getLocale() {
    Locale? locale;
    String code = CacheHelper.countryCode;
    List<String> lang = code.split('-');
    locale = (code == Language.fsLan.countryCode)
        ? Get.deviceLocale
        : Locale(lang[0], lang[1]);
    return locale;
  }

  static void updateLocale(String countryCode, {bool isL10n = false}) {
    List<String> lang = countryCode.split('-');
    Get.updateLocale((countryCode == Language.fsLan.countryCode)
        ? Get.deviceLocale!
        : Locale(lang[0], lang[1]));
    CacheHelper.saveCountryCode(countryCode);
    if (isL10n) {
      L10nAppState.setting.changeLocale!();
    }
  }
}

mian.dart类

import 'package:flutter/material.dart';

import 'app.dart';
import 'core/cache/cache/cache.dart';
import 'l10n_app.dart';

void main() async {
  await Cache.instance.init();
  runApp(L10nApp()); //flutter_localizations与GetX配合版的多语言
  // runApp(const App()); //GetX版多语言
}

5.调用

  1. 直接使用 Text(AppLocalizations.of(context).helloWorld)
  2. 扩展使用
    - 扩展BuildContext
extension BuildContextExtension on BuildContext {    
    AppLocalizations get l10n => AppLocalizations.of(this);    
}
 - 使用   
 Text(context.l10n.helloWorld)  

6.多语言切换

l10n_multi_language_view.dart类

import 'package:brave_component/core/enums/language.dart';
import 'package:brave_component/l10n/l10n.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

import '../../../../../core/res/colours.dart';
import '../../../../../widgets/base/texts.dart';
import 'l10n_multi_language_logic.dart';

class L10nMultiLanguagePage extends StatelessWidget {
  L10nMultiLanguagePage({super.key});

  final logic = Get.find<L10nMultiLanguageLogic>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Texts.fontSize18Normal(context.l10n.multiLanguage,
            color: Colours.titleColor),
        leading: GestureDetector(
          onTap: () {
            Get.back(result: 'changeLanguage');
          },
          child: const Icon(Icons.arrow_back),
        ),
      ),
      body: Container(
        padding: const EdgeInsets.symmetric(vertical: 15),
        // child: ListView(
        //   children: ListTile.divideTiles(
        //           context: context,
        //           tiles: Language.values
        //               .map((e) =>
        //                   GetBuilder<MultiLanguageLogic>(builder: (logic) {
        //                     return ListTile(
        //                       title: Texts.fontSize14Normal(e.title,
        //                           color: Colours.titleColor),
        //                       trailing: e.countryCode == logic.countryCode
        //                           ? const Icon(Icons.check,
        //                               color: Colours.primaryColor)
        //                           : null,
        //                       onTap: () {
        //                         logic.changeLanguage(e.countryCode);
        //                       },
        //                     );
        //                   }))
        //               .toList())
        //       .toList(),
        // ),
        child: ListView.separated(
            itemBuilder: (context, index) {
              return _itemContent(context, index);
            },
            separatorBuilder: (_, index) => const Divider(),
            itemCount: Language.values.length),
      ),
    );
  }

  Widget _itemContent(BuildContext context, int index) {
    return GetBuilder<L10nMultiLanguageLogic>(builder: (logic) {
      return Container(
        padding: const EdgeInsets.symmetric(horizontal: 15),
        height: 44,
        child: GestureDetector(
          onTap: () {
            logic.changeLanguage(Language.values[index].countryCode);
          },
          child: Row(
            children: [
              Expanded(
                  child: Texts.fontSize14Normal(Language.values[index].title,
                      color: Colours.titleColor)),
              Visibility(
                  visible:
                      logic.countryCode == Language.values[index].countryCode,
                  child: const Icon(Icons.check, color: Colours.primaryColor))
            ],
          ),
        ),
      );
    });
  }
}


l10n_multi_language_logic.dart类

import 'package:brave_component/core/cache/helpers/cache_helper.dart';
import 'package:brave_component/core/utils/language_utils.dart';
import 'package:get/get.dart';

class L10nMultiLanguageLogic extends GetxController {
  late String countryCode;

  @override
  void onInit() {
    super.onInit();
    countryCode = CacheHelper.countryCode;
  }

  void changeLanguage(String code) {
    countryCode = code;
    LanguageUtils.updateLocale(code, isL10n: true);//切换Locale
    update();
  }
}

l10n_multi_language_binding.dart类

import 'package:get/get.dart';

import 'l10n_multi_language_logic.dart';

class L10nMultiLanguageBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => L10nMultiLanguageLogic());
  }
}

language 类

enum Language {
  fsLan(title: "跟随系统语言", countryCode: "fs-Lan"),
  zhCN(title: "简体中文", countryCode: "zh-CN"),
  zhHK(title: "繁体中文", countryCode: "zh-HK"),
  enUS(title: "English", countryCode: "en-US");

  final String title;
  final String countryCode;

  const Language({required this.title, required this.countryCode});
}

这里关于GetX的binding用法不会的可以参考Flutter GetX使用—简洁的魅力!这个博主开发的GetX插件,生成模版代码提高研发效率,建议看看用起来。

持久化就不赘述了,参考源码
源码

下一篇 多语言方案二:GetX 版