【第六天 - Flutter 多国语系】

前言

今日的程序码 => GITHUB
这边我想要介绍如何切换语言、设定 App 初始的语言,且下此开启 App 时也会记住已经被切换过的语言。

备注:

这边的教学,功能正常,但写法不一定是最好的。这边推荐另外的套件

设定 YAML 档案

  flutter_localizations:
    sdk: flutter
  shared_preferences: ^2.0.7
- - - - - - - - - - - - - - - - - - - - -
  assets:
    - language/

建立 Json 档案

建立一个 language 在专案目录底下建立两个 Json

  • en.json
{
 "name": "flutter_localizations example",
 "introduce": "Hello"
}
  • zh.json
{
 "name": "语言切换范例",
 "introduce" : "你好呀"
}

大致上的逻辑

会给予 sharedpreferences 一个预设的语言 data(zh),手机一打开时,会在 didChangeDependencies 里面去读取 sharedpreferences,进而去设定 local 的地区是属於什麽。

MyApp

  • supportedLocales = App 要支援的语言
  • localizationsDelegates = 委托确保加载正确语言的本地化数据
  • localeResolutionCallback = 检查手机是否支援这个语言
  • locale = 现在手机的语言是什麽
  • AppLocalizations = 是我们自己建立管理语言的一个 class
class MyApp extends StatefulWidget {
  MyApp({Key? key}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();

  /// 当地区更改时,重新设定地区,当使用者按下变换语言时,会触发。
  static void setLocale(BuildContext context, Locale newLocale) {
    _MyAppState? state = context.findAncestorStateOfType<_MyAppState>();
    state!.changeLocale(newLocale);
  }
}

class _MyAppState extends State<MyApp> {
  Locale _locale = new Locale.fromSubtags(languageCode: 'zh');
  /// 更改地区
  void changeLocale(Locale locale) {
    setState(() {
      this._locale = locale;
    });
  }

  @override
  void didChangeDependencies() async {
    super.didChangeDependencies();
    final languageApp = AppLocalizations();
    final localeKey = await languageApp.readLocaleKey();
    if (localeKey == "en") {
      this._locale = new Locale("en", "EN");
    } else {
      this._locale = new Locale.fromSubtags(languageCode: 'zh');
    }
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        supportedLocales: [
          Locale('en', 'US'),
          const Locale.fromSubtags(languageCode: 'zh'),
        ],
        // These delegates make sure that the localization data for the proper language is loaded
        // 委托确保加载正确语言的本地化数据
        localizationsDelegates: [
          // This class will be added later
          // A class which loads the translations from JSON files
          AppLocalizations.delegate,
          // A class which loads the translations from JSON files
          GlobalMaterialLocalizations.delegate,
          // Built-in localization of basic text for Material widgets
          GlobalWidgetsLocalizations.delegate,
        ],
        locale: _locale,
        // Returns a locale which will be used by the app
        localeResolutionCallback: (locale, supportedLocales) {
          // Check if the current device locale is supported
          // 检查手机是否支援这个语言
          for (var supportedLocaleLanguage in supportedLocales) {
            if (supportedLocaleLanguage.languageCode == locale?.languageCode &&
                supportedLocaleLanguage.countryCode == locale?.countryCode) {
              return supportedLocaleLanguage;
            }
          }
          // If device not support with locale to get language code then default get first on from the list
          return supportedLocales.first;
        },
        home: HomePage());
  }
}

AppLocalizations 管理语言的 class

class AppLocalizations {
  final Locale locale;
  AppLocalizations({this.locale = const Locale.fromSubtags(languageCode: 'zh')});
  /// Helper method to keep the code in the widgets concise
  /// Localizations are accessed using an InheritedWidget "of" syntax
  /// 访问本地化
  static AppLocalizations? of(BuildContext context) {
    return Localizations.of<AppLocalizations>(context, AppLocalizations);
  }
  /// 储存 SharedPreferences
  void keepLocaleKey(String localeKey) async {
    final _prefs = await SharedPreferences.getInstance();
    await _prefs.remove("localeKey");
    await _prefs.setString("localeKey", localeKey);
  }
  /// 读取 SharedPreferences
  Future<String> readLocaleKey() async {
    final _prefs = await SharedPreferences.getInstance();
    // 初始化最一刚开始的语言
    return _prefs.getString("localeKey")??'zh';
  }
  
  /// 更改语言,重新设定语言
  void setLocale(BuildContext context, Locale locale) async {
    // keep value in shared pref
    keepLocaleKey(locale.languageCode);
    print("key language :${locale.languageCode}");
    MyApp.setLocale(context, locale);
  }
  /// Static member to have a simple access to the delegate from the MaterialApp
  /// 提供 Main Page 可以直接访问。
  static const LocalizationsDelegate<AppLocalizations> delegate =
  _AppLocalizationsDelegate();

  late Map<String, String> _localizedStrings;
  /// Load the language JSON file from the "lang" folder
  /// 读取 Json 格式
  Future<bool> load() async {
    String jsonString =
    await rootBundle.loadString('language/${locale.languageCode}.json');
    Map<String, dynamic> jsonMap = json.decode(jsonString);

    _localizedStrings = jsonMap.map((key, value) {
      return MapEntry(key, value.toString());
    });

    return true;
  }

  /// This method will be called from every widget which needs a localized text
  /// 提供每一个需要转换语言的文字
  String translate(String key) {
    return _localizedStrings[key]!;
  }
}

/// LocalizationsDelegate is a factory for a set of localized resources
/// In this case, the localized strings will be gotten in an AppLocalizations object
/// 本地化的字符串将在 AppLocalizations 对像中获取
class _AppLocalizationsDelegate
    extends LocalizationsDelegate<AppLocalizations> {
  // This delegate instance will never change (it doesn't even have fields!)
  // It can provide a constant constructor.
  const _AppLocalizationsDelegate();
  /// 之泉的语言代码
  @override
  bool isSupported(Locale locale) {
    // Include all of your supported language codes here
    return ['en', 'zh'].contains(locale.languageCode);
  }
  /// 读取 Json
  @override
  Future<AppLocalizations> load(Locale locale) async {
    // AppLocalizations class is where the JSON loading actually runs
    AppLocalizations localizations = new AppLocalizations(locale: locale);
    await localizations.load();
    return localizations;
  }
  /// 使否重新 reload
  @override
  bool shouldReload(_AppLocalizationsDelegate old) => false;
}

设定需要改的文字

Text(AppLocalizations.of(context)!.translate('introduce')),

更改语言按钮时

AppLocalizations localeApp = AppLocalizations();

// 之後再按钮的 onPressed 里面 
onPressed: () async {
  if (await localeApp.readLocaleKey() == "zh") {
    localeApp.setLocale(context, Locale("en", "EN"));
  } else {
    localeApp.setLocale(
    context, Locale.fromSubtags(languageCode: 'zh'));
  }
}

<<:  Day12 数据图表化 - 如何建立 Visualize

>>:  Day6 跟着官方文件学习Laravel-DB设定

LocalDB 无法开启时,如何解决

用新版Visual studio 2019开启旧版SQL Server 2012的mdf档时,却出现...

路由把关者- Navigation Guards

前言 Vue Router 提供 Navigation Guards,可以在路由变更前後去呼叫相关的...

Day 4 python回圈

今天我们要介绍的是python当中的FOR回圈,所谓的回圈就是只我们如果要在某个条件下要重复做某些事...

[第18天]理财达人Mx. Ada-证券扣款帐户银行余额资讯

前言 本文说明查询证券扣款帐户银行余额资讯。 程序实作 程序 # 扣款帐户余额资讯 balance ...

#12 No-code 之旅 — 在 Next.js 专案中显示 RSS 的资料 ft. RSS Parser

嗨嗨嗨!昨天使用 Notion SDK 显示我的 Notion page 里面的内容,可以在这里看看...