以$t形式使用flutter多語言

前言

關於flutter國際化的具體介紹,你們能夠移步國際化Flutter App前端

本文主要介紹在flutter如何使用多語言而且如何像web使用i18n同樣使用多語言($t)和實現語言切換,這對前端開發人員會更加友好。git

項目地址

flutter-ui, 這是包含flutter組件介紹的開源項目,歡迎stargithub

flutter_intl 本教程的項目源碼,歡迎starweb

效果

英文
中文

如何使用

添加依賴

  • 在pubspec.yaml中引入依賴
dependencies:
  flutter_localizations:
    sdk: flutter
複製代碼
  • 執行
flutter packages get
複製代碼

新建文件locale

locale
    |-en.json
    |-zh.json
複製代碼

多語言的文件json

  • en.json
{
    "title_page": "i18n",
    "title_appbar": "i18n",
    "content": {
        "currentLanguage": "The current language is English",
        "zh": "zh",
        "en": "en"
    }
}
複製代碼
  • zh.json
{
    "title_page": "國際化例子",
    "title_appbar": "國際化例子",
    "content": {
        "currentLanguage": "當前語言是中文",
        "zh": "中文",
        "en": "英文"
    }
}
複製代碼

lib下新建lang

lang
  |- config.dart
  |- index.dart
複製代碼
  • config.dart
import 'package:flutter/material.dart';

class ConfigLanguage {
  static List<Locale> supportedLocales = [
    Locale('zh', 'CH'),
    Locale('en', 'US')
  ];

  static Map<String, dynamic> supportLanguage = {
    "zh": {"code": "zh", "country_code": "CH"},
    "en": {"code": "en", "country_code": "US"},
  };

  static dynamic defaultLanguage = {
    "code": "zh",
    "country_code": "CH"
  };
}
複製代碼

config.dart做用主要是將配置性的內容統一到一個文件中app

  • index.dart
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:flutter/services.dart' show rootBundle;
import 'package:flutter/foundation.dart' show SynchronousFuture;
import 'package:flutter_intl/lang/config.dart' as I18NConfig;
class AppLocalizations {
  Locale _locale;
  static Map<String, dynamic> jsonLanguage; // 語言包
  static AppLocalizations _inst; // inst

  AppLocalizations(this._locale);

  // 初始化 localizations
  static Future<AppLocalizations> init(Locale locale) async {
    _inst = AppLocalizations(locale);
    await getLanguageJson();
    return _inst;
  }

  // 獲取語言包
  static Future getLanguageJson() async {
    Locale _tmpLocale = _inst._locale;
    print('獲取語言包的語種; ${_tmpLocale.languageCode}');
    String jsonLang;
    try {
      jsonLang = await rootBundle.loadString('locale/${_tmpLocale.languageCode}.json');
    } catch (e) {
      print('出錯了');
      _inst._locale = Locale(I18NConfig.ConfigLanguage.defaultLanguage['code']);
      jsonLang = await rootBundle.loadString('locale/${I18NConfig.ConfigLanguage.defaultLanguage['code']}.json');
    }
    jsonLanguage = json.decode(jsonLang);
    print("當前語言: ${_inst._locale}");
    print("數據: $jsonLanguage");
  }

// $t 封裝,目的是爲了能夠使用$t來獲取多語言數據
  static String $t(String key) {
    var _array = key.split('.');
    var _dict = jsonLanguage;
    var retValue = '';
    try {
      _array.forEach((item) {
        if(_dict[item].runtimeType == Null) {
          retValue = key;
          return;
        }
        if (_dict[item].runtimeType != String) {
          _dict = _dict[item];
        } else {
          retValue = _dict[item];
        }
      });
      retValue = retValue.isEmpty ? _dict : retValue;
    } catch (e) {
      print('i18n exception');
      print(e);
      retValue = key;
    }

    return retValue ?? '';
  }

}


// 實現LocalizationsDelegate協議,用於初始化Localizations類
class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
  final Locale locale;
  AppLocalizationsDelegate([this.locale]);

  @override
  bool isSupported(Locale locale) {
    return I18NConfig.ConfigLanguage.supportLanguage.keys
      .toList()
      .contains(locale.languageCode);
  }

// 在這裏初始化Localizations類
  @override
  Future<AppLocalizations> load(Locale _locale) async {
    print('將要加載的語言: $_locale');
    return await AppLocalizations.init(_locale);
    // return SynchronousFuture<AppLocalizations>(
    // AppLocalizations(_locale)
    // );
  }

  @override
  bool shouldReload(LocalizationsDelegate<AppLocalizations> old) {
    // flase時,不執行上述重寫函數
    return false;
  }
}
複製代碼

詳情請看代碼註釋~~~~~~~~~less

概況一下就是async

實現一個LocalizationsDelegate協議和實現一個Localizations類,而後引入到main.dart中的MaterialApp中ide

處理main.dart文件

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_intl/lang/index.dart'
  show AppLocalizations, AppLocalizationsDelegate;
import 'package:flutter_intl/lang/config.dart' show ConfigLanguage;


void main () => runApp(MainApp());
GlobalKey<_ChangeLocalizationsState> changeLocalizationsStateKey = new GlobalKey<_ChangeLocalizationsState>();
class MainApp extends StatefulWidget {
  @override
  _MainAppState createState() => _MainAppState();
}

class _MainAppState extends State<MainApp> {
  // 定義全局 語言代理
  AppLocalizationsDelegate _delegate;

  @override
  void initState() {
    // TODO: implement initState
    _delegate = AppLocalizationsDelegate();
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // locale: Locale('zh', 'CH'),
      localeResolutionCallback: (deviceLocale, supportedLocal) {
        print('當前設備語種 deviceLocale: $deviceLocale, 支持語種 supportedLocale: $supportedLocal}');
        // 判斷傳入語言是否支持
        Locale _locale = supportedLocal.contains(deviceLocale) ? deviceLocale : Locale('zh', 'CN');
        return _locale;
      },
      onGenerateTitle: (context) {
        // 設置多語言代理
        // AppLocalizations.setProxy(setState, _delegate);
        return AppLocalizations.$t('title_page');
      },
      // localizationsDelegates 列表中的元素時生成本地化集合的工廠
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,   // 爲Material Components庫提供本地化的字符串和其餘值
        GlobalWidgetsLocalizations.delegate,    // 定義widget默認的文本方向,從左往右或從右往左
        _delegate
      ],
      supportedLocales: ConfigLanguage.supportedLocales,
      initialRoute: '/',
      routes: {
        '/': (context) => 
        // Home()
        Builder(builder: (context) {
          return ChangeLocalizations(
            key: changeLocalizationsStateKey,
            child: Home()
          );
        })
      }
    );
  }
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Locale locale = Localizations.localeOf(context);
    return Scaffold(
      appBar: AppBar(title: Text('${AppLocalizations.$t('title_appbar')}'),),
      body: ListView(
        children: <Widget>[
          Container(
            margin: EdgeInsets.only(top: 60),
            alignment: Alignment.center,
            child: Text('${locale.languageCode} ${locale.toString()}'),
          ),
          Container(
            alignment: Alignment.center,
            child: Text('${AppLocalizations.$t('content.currentLanguage')}'),
          ),
          Wrap(
            spacing: 8.0,
            alignment: WrapAlignment.center,
            children: <Widget>[
              ActionChip(
                backgroundColor: Theme.of(context).primaryColor,
                onPressed: () {
                  changeLocalizationsStateKey.currentState.changeLocale(Locale('en', 'US'));
                },
                label: Text('${AppLocalizations.$t('content.en')}'),
              ),
              ActionChip(
                backgroundColor: Theme.of(context).primaryColor,
                onPressed: () {
                  changeLocalizationsStateKey.currentState.changeLocale(Locale('zh', 'CH'));
                },
                label: Text('${AppLocalizations.$t('content.zh')}'),
              )
            ],
          )
        ],
      )
    );
  }
}

class ChangeLocalizations extends StatefulWidget {
  final Widget child;
  ChangeLocalizations({Key key, this.child}):super(key: key);
  @override
  _ChangeLocalizationsState createState() => _ChangeLocalizationsState();
}

class _ChangeLocalizationsState extends State<ChangeLocalizations> {
  Locale _locale;
  @override
  void initState() {
    super.initState();
  }
  @override
  void didChangeDependencies() async {
    super.didChangeDependencies();
    // 獲取當前設備的語言
    _locale = Localizations.localeOf(context);
    print('設備語言: $_locale');
  }
  changeLocale(Locale locale) {
    setState(() {
      _locale = locale;
    });
  }
  @override
  Widget build(BuildContext context) {
    return Localizations.override(
      context: context,
      locale: _locale,
      child: widget.child,
    );
  }
}
複製代碼
  • 在MaterialApp中指定localizationsDelegate和supportedLocales
    • localeResolutionCallback:在應用獲取用戶設置的語言區域時回調,能夠根據須要return對應的Locale
    • onGenerateTitle: 返回對應的多語言應用標題
    • localizationsDelegates:localizationsDelegates 列表中的元素時生成本地化集合的工廠
    • supportedLocales: app支持的語言種類
  • Home類就是顯示的類
    • Localizations.localeOf(context).languageCode能夠獲取當前app的語言類型
    • AppLocalizations.$t('content.currentLanguage')像web同樣玩耍多語言內容

到這裏就已經能夠愉快的玩耍多語言了,用戶設置不一樣的語言就會加載不一樣的語言包函數

下面實如今app內的語言切換

  • ChangeLocalizations類使用Localizations的override方法,代碼如上
    • 使用GlobalKey調用ChangeLocalizations的內部方法,GlobalKey<_ChangeLocalizationsState> changeLocalizationsStateKey = new GlobalKey<_ChangeLocalizationsState>(); 咱們也能夠將GlobalKey放入到provide中,這樣能夠實現多個頁面進行changeLocalizationsStateKey的訪問
    • 修改語言調用changeLocale方法,changeLocalizationsStateKey.currentState.changeLocale(Locale('en', 'US'));

最後

歡迎更多學習flutter的小夥伴加入QQ羣 Flutter UI: 798874340

敬請關注咱們正在開發的: efoxTeam/futter-ui

做者

相關文章
相關標籤/搜索