123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- // ignore_for_file: non_constant_identifier_names
- import 'package:flutter/services.dart';
- import 'package:flutter/widgets.dart';
- import 'types.dart';
- import 'key_book.dart';
- import 'dart:convert';
- export 'key_book.dart';
- export 'types.dart' hide FTrMapPickExtension, ModuleBase, IPropQueryable;
- const String _PACKAGE_NAME = "fis_i18n";
- typedef FTrKeybookBuilder = Future<FTrKeybook> Function();
- typedef FI18nLocaleUpdater = void Function(Locale locale);
- /// 中文
- const Locale CHINESE_LOCALE = const Locale("zh", "CN");
- /// 英文
- const Locale ENGLISH_LOCALE = const Locale("en", "US");
- /// 俄语
- const Locale RUSSIAN_LOCALE = const Locale("ru", "RU");
- /// 西班牙语
- const Locale SPANISH_LOCALE = const Locale("es", "ES");
- /// 罗马尼亚语
- const Locale ROMANIA_LOCALE = const Locale("ro", "RO");
- AssetBundle _assetBundle = rootBundle;
- /// 翻译字典选项
- ///
- /// [locale] 语言
- ///
- /// [builder] 字典建造器
- class FTrKeybookOption {
- const FTrKeybookOption(this.locale, this.builder);
- final Locale locale;
- final FTrKeybookBuilder builder;
- /// 中文字典建造器
- static final FTrKeybookOption ChineseOption = FTrKeybookOption(
- CHINESE_LOCALE,
- () => _buildInnerBoook(CHINESE_LOCALE),
- );
- /// 英文字典建造器
- static final FTrKeybookOption EnglishOption = FTrKeybookOption(
- ENGLISH_LOCALE,
- () => _buildInnerBoook(ENGLISH_LOCALE),
- );
- /// 俄语字典建造器
- static final FTrKeybookOption RussianOption = FTrKeybookOption(
- RUSSIAN_LOCALE,
- () => _buildInnerBoook(RUSSIAN_LOCALE),
- );
- /// 西班牙语字典建造器
- static final FTrKeybookOption SpanishOption = FTrKeybookOption(
- SPANISH_LOCALE,
- () => _buildInnerBoook(SPANISH_LOCALE),
- );
- /// 罗马尼亚字典建造器
- static final FTrKeybookOption RomaniaOption = FTrKeybookOption(
- ROMANIA_LOCALE,
- () => _buildInnerBoook(ROMANIA_LOCALE),
- );
- }
- /// 国际化翻译字典
- FTrKeybook get i18nBook => FI18n.ins.currentBook;
- /// 国际化
- class FI18n {
- FI18n._();
- static FI18n? _singleton;
- /// 单例
- static FI18n get ins {
- if (_singleton == null) {
- throw Exception("There aren't any instance of FI18n.");
- }
- return _singleton!;
- }
- late FTrKeybook _currentBook;
- late FI18nLocaleUpdater _localeUpdater;
- final Map<Locale, FTrKeybookBuilder> _bookMap = {};
- /// 当前语言字典
- FTrKeybook get currentBook => _currentBook;
- /// 当前是否中文
- bool get isCurrentChinese => currentBook.isCurrentChinese;
- /// 支持的语言
- List<Locale> get supportedLocales => _bookMap.keys.toList();
- /// 设置内置资源包
- static void setAssetBundle(AssetBundle bundle) {
- _assetBundle = bundle;
- }
- /// 初始化
- static Future<void> init(
- FI18nLocaleUpdater localeUpdater,
- List<FTrKeybookOption> bookOptions,
- ) async {
- if (_singleton != null) {
- throw Exception("FI18n has been init.");
- }
- _singleton = FI18n._();
- _singleton!._localeUpdater = localeUpdater;
- await _singleton!._buildInstance(bookOptions);
- }
- Future<void> _buildInstance(List<FTrKeybookOption> bookOptions) async {
- bookOptions.forEach((option) {
- if (_bookMap.containsKey(option.locale)) {
- throw Exception("FI18n init: The same locale value already exists.");
- }
- setKeyBook(option.locale, option.builder);
- });
- }
- /// 加载(初始语言,init之后)
- static Future<void> 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(
- "FI18n load error: No book-builder match the target locale.");
- _singleton!._currentBook = await bookBuilder();
- }
- /// 切换语言
- Future<Locale> 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<FTrKeybook> _buildInnerBoook(Locale locale) async {
- final code = locale.toCodeString();
- final assetKey = "packages/$_PACKAGE_NAME/assets/$code.json";
- final byteData = await rootBundle.load(assetKey);
- final text = utf8.decode(byteData.buffer.asUint8List());
- final book = FTrKeybook.createFromJson(text);
- return book;
- }
|