import 'package:fis_i18n/i18n.dart'; import 'package:fis_i18n/types.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; import 'package:flyinsonolite/localization/fis_keybook.dart'; typedef FTrKeybookBuilder = Future Function(); typedef FI18nLocaleUpdater = void Function(Locale locale); AssetBundle _assetBundle = rootBundle; /// 翻译字典选项 /// /// [locale] 语言 /// /// [builder] 字典建造器 class FISTrKeybookOption { const FISTrKeybookOption(this.locale, this.builder); final Locale locale; final FTrKeybookBuilder builder; /// 中文字典建造器 static final FISTrKeybookOption ChineseOption = FISTrKeybookOption( CHINESE_LOCALE, () => _buildInnerBoook(CHINESE_LOCALE), ); /// 英文字典建造器 static final FISTrKeybookOption EnglishOption = FISTrKeybookOption( ENGLISH_LOCALE, () => _buildInnerBoook(ENGLISH_LOCALE), ); } /// 国际化翻译字典 FISTrKeybook get fisI18nBook => FISI18n.ins.currentBook; /// 国际化 class FISI18n { FISI18n._(); static FISI18n? _singleton; /// 单例 static FISI18n get ins { if (_singleton == null) { throw Exception("There aren't any instance of FI18n."); } return _singleton!; } late FISTrKeybook _currentBook; late FI18nLocaleUpdater _localeUpdater; final Map _bookMap = {}; /// 当前语言字典 FISTrKeybook get currentBook => _currentBook; /// 当前是否中文 bool get isCurrentChinese => currentBook.isCurrentChinese; /// 支持的语言 List get supportedLocales => _bookMap.keys.toList(); /// 设置内置资源包 static void setAssetBundle(AssetBundle bundle) { _assetBundle = bundle; } /// 初始化 static Future init( FI18nLocaleUpdater localeUpdater, List bookOptions, ) async { if (_singleton != null) { throw Exception("FI18n has been init."); } _singleton = FISI18n._(); _singleton!._localeUpdater = localeUpdater; await _singleton!._buildInstance(bookOptions); } Future _buildInstance(List bookOptions) async { for (var option in bookOptions) { if (_bookMap.containsKey(option.locale)) { throw Exception("FI18n init: The same locale value already exists."); } setKeyBook(option.locale, option.builder); } } /// 加载(初始语言,init之后) static Future load(Locale locale) async { // 语言+国家 精准匹配 var bookBuilder = _singleton!._bookMap[locale]; // 语言匹配 if (bookBuilder == null) { final matchKey = _singleton!._bookMap.keys.firstWhere( (x) => x.languageCode == locale.languageCode, orElse: () => ENGLISH_LOCALE, ); bookBuilder = _singleton!._bookMap[matchKey]; } if (bookBuilder == null) { throw Exception( "FISI18n load error: No book-builder match the target locale."); } _singleton!._currentBook = await bookBuilder(); } /// 切换语言 Future switchLanguage([Locale? locale]) async { Locale matchLocale; if (locale == null) { // 顺序找下一个字典 final keys = _bookMap.keys.toList(); final curIdx = keys.indexOf(currentBook.locale); int nextIdx = curIdx + 1; if (nextIdx >= keys.length) nextIdx = 0; matchLocale = keys[nextIdx]; } else { // 优先语言Code和国家Code双匹配,否则选语言Code匹配 final langCodeMatchList = _bookMap.keys.where((x) => x.languageCode == locale.languageCode); if (langCodeMatchList.isEmpty) { // 无匹配 throw Exception( "FI18n switchLanguage: No keybook found for the target locale."); } if (langCodeMatchList.length > 1) { // 查找双匹配 matchLocale = langCodeMatchList.firstWhere( (x) => x.countryCode == locale.languageCode, orElse: () => langCodeMatchList.first, ); } else { // 单匹配 matchLocale = langCodeMatchList.first; } } FTrKeybookBuilder builder = _bookMap[matchLocale]!; _currentBook = await builder(); _localeUpdater(matchLocale); return matchLocale; } /// 设置翻译字典(相同语言会覆盖) void setKeyBook(Locale locale, FTrKeybookBuilder bookBuilder) { _bookMap[locale] = bookBuilder; } /// 根据字典树翻译 /// /// [keyTree] 字典树,以.分隔,例:common.loading String translate(String keyTree) { final tiers = keyTree.split('.'); dynamic curr = currentBook; for (var key in tiers) { if (curr is IPropQueryable) { curr = curr.getProp(key); } else { return keyTree; } } return curr; } } Future _buildInnerBoook(Locale locale) async { final code = locale.toCodeString(); final assetKey = "assets/languages/$code.json"; final text = await _assetBundle.loadString(assetKey, cache: false); final book = FISTrKeybook.createFromJson(text); return book; }