preface
We have written about the use of multiple languages of Flutter before. If you are interested in using multiple languages of Flutter in $T form, you can go to the internationalization of Flutter App for detailed introduction
This article focuses on how to package a plugin for Flutter to reduce the workload of developers with multiple languages of Flutter
Access to the use of
FlutterLocalization
The effect
Multi-language Plugin features
- Flutter connects to Efox multilanguage platform and supports switching between local and Efox platforms and languages
- Support language customization, support simple and traditional Chinese
- Open configuration items:
- Supported languages
- The default language
- Language mapping
- Local language path
- Efox platform language path
- Whether to load local multilanguage
- Accessible method
- If access to load the local language: AppLocalizations isLocale
- If modify the loading local language: AppLocalizations changeIsLocale (true | false).
- Gets the current language: AppLocalizations localeLang
- $t(‘title_page’)
Plugin packages and Dart Packages
- Plugin packages are used when you need to expose Native apis to others, using Platform Channels and containing Androiod/iOS Native logic. There is also an internal Flutter project under the Example directory that can be run directly for code testing
- Dart packages are used when you need to develop a pure Dart component (such as a custom Weidget). There is no Native code inside. Code tests can be introduced via a local path through your own build up of the Flutter project
The new package
Multilanguage plugins create a new Dart package for code lifting
Step 1:
Access to the multiple languages of flutter specifies localizationsDelegates and supportedLocales of the MaterialApp, while localeResolutionCallback is called back when the app retrievesthe user-set language region
localizationsDelegates: AppLocal.localizationsDelegates,
supportedLocales: AppLocal.supportedLocales,
localeResolutionCallback: AppLocal.localeResolutionCallback,
Copy the code
Therefore, you need to provide an AppLocal class to implement the three instances
class AppLocal {
static 可迭代<LocalizationsDelegate<dynamic>> _localizationsDelegates = [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
AppLocalizationsDelegate()
];
// The supported language
static 可迭代<Locale> _supportedLocales = ConfigLanguage.supportedLocales;
// The application gets a locale callback
static Locale _localeResolutionCallback(deviceLocale, supportedLocal) {
print(
'deviceLocale: $deviceLocale, supportedLocale: $supportedLocal}');
// null [] [en_US] [en_US, zh_CH] Locale('en', 'US') Different mobile phones have different return parameters for obtaining the language, so you need to perform corresponding processing according to the return parameters
var useDeciceLocale;
if(deviceLocale ! =null &&
deviceLocale.runtimeType.toString().contains('List') &&
deviceLocale.isNotEmpty) {
useDeciceLocale = deviceLocale[0];
} else {
if (deviceLocale.runtimeType.toString() == 'Locale') {
useDeciceLocale = deviceLocale;
} else {
useDeciceLocale = null; }}print(
'Phone gets matched language: $useDeciceLocale,${useDeciceLocale.runtimeType.toString()} ${useDeciceLocale.runtimeType.toString() == 'Locale'}');
Locale _locale;
bool hasLanguage = false;
if(useDeciceLocale ! =null) {
for (num i = 0; i < supportedLocal.length; i++) {
if (useDeciceLocale.scriptCode == 'Hant') {
if (useDeciceLocale.languageCode == supportedLocal[i].languageCode &&
useDeciceLocale.scriptCode == supportedLocal[i].scriptCode) {
hasLanguage = true;
useDeciceLocale = supportedLocal[i];
print($useDeciceLocale = $useDeciceLocale);
break; }}else {
if (useDeciceLocale.languageCode == supportedLocal[i].languageCode) {
hasLanguage = true;
useDeciceLocale = supportedLocal[i];
print('Normal language code matches: $useDeciceLocale');
break;
}
}
}
_locale = hasLanguage
? useDeciceLocale
: Locale.fromSubtags(
languageCode: ConfigLanguage.defaultLanguage['language_code'],
scriptCode: ConfigLanguage.defaultLanguage['script_code']);print(
'${hasLanguage ? 'Mobile system language supported by this app, using the system specified language: $_locale' : 'Mobile system language is not supported by this app, use the app to specify the default language: $_locale'}');
} else {
_locale = Locale.fromSubtags(
languageCode: ConfigLanguage.defaultLanguage['language_code'],
scriptCode: ConfigLanguage.defaultLanguage['script_code']);print('Mobile system language is not supported by this app, use the app to specify the default language: $_locale');
}
return _locale;
}
static get supportedLocales => _supportedLocales;
static get localizationsDelegates => _localizationsDelegates;
static get localeResolutionCallback => _localeResolutionCallback;
}
Copy the code
Step 2:
In localizationsDelegates, in addition to the delegate provided by the flutter itself, we will need to specify a localization delegate as follows, AppLocalizations is our data store and Controller class, and it is used to determine whether the language supports loading and reloading logic processing. AppLocalizations are our data store and Controller class
class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
AppLocalizationsDelegate();
@override
bool isSupported(Locale locale) {
return ConfigLanguage.supportedLocales.contains(locale);
}
@override
Future<AppLocalizations> load(Locale locale) async {
LocalStorage.get('lang').then((lang) async {
print('Locally cached language: $lang');
AppLocalizations._localeLang = lang;
if (lang == null) {
print('Locale: $locale');
return await AppLocalizations.init(locale);
} else {
print('Language to be loaded lang: $lang');
List<String> langCode = lang.split(The '-');
if (langCode.length > 1) {
return await AppLocalizations.init(Locale.fromSubtags(
languageCode: langCode[0], scriptCode: langCode[1]));
} else {
return await AppLocalizations.init(Locale(langCode[0])); }}}); }@override
bool shouldReload(LocalizationsDelegate<AppLocalizations> old) {
// When false, the above overwrite function is not executed
return false; }}Copy the code
Step 3:
AppLocalizations class, which stores multilingual data, data processing and data initialization, provides developers with methods under this class. Methods to be implemented:
- Receive the addSupportLanguage method for parameter configurations (supported language, default language, language mapping, local path, efox platform path, whether to load local or not)
- Gets the localeLang method for the language
- Page refresh is required during language switch, so you need to save setState’s setProxy method (set language switch proxy)
- The internal init method and the getLanguageJson method to load the language package
- Need to load the changeIsLocale method of the local language
- Modify the changeLanguage method for the current language
- The $t method of the read language
class AppLocalizations {
Locale _locale;
static AppLocalizations _inst; / / AppLocalizations instance
static Map<String.dynamic> _jsonLanguage = {}; / / language pack
static Function _setState; // Top-level parent setState
static BuildContext _context;
static String _localePath; // Local multilingual path
static String _I18nHost; // Efox platform multilanguage path
static bool _isLocale = true; // Whether to load local multilanguage
static bool _hasConfigLocale = false; // Whether to manually configure whether to load local multilanguages
static String _localeLang; // Cache local multilingual languages
static bool get isLocale => _isLocale;
static String get localeLang {
return _localeLang ?? Localizations.localeOf(_context).toString();
}
AppLocalizations(this._locale);
// Add supported languages
static void addSupportLanguage({
List<Locale> supportedLocales,
Map<String.String> defaultLanguage,
Map<String.String> mapLanguage,
String localePath,
String I18nHost,
bool isLocale,
}) {
if(supportedLocales ! =null) {
ConfigLanguage.supportedLocales.addAll(supportedLocales);
}
if(defaultLanguage ! =null) {
ConfigLanguage.defaultLanguage.addAll(defaultLanguage);
}
if(mapLanguage ! =null) {
ConfigLanguage.mapLanguage.addAll(mapLanguage);
}
if(isLocale ! =null) {
_hasConfigLocale = true;
_isLocale = isLocale;
}
_localePath = localePath;
_I18nHost = I18nHost;
}
// Set the language switch agent
static void setProxy(Function setState, BuildContext context) async {
_setState = setState;
_context = context;
}
// Initialize localizations
static Future<AppLocalizations> init(Locale locale) async {
_inst = AppLocalizations(locale);
await getLanguageJson();
_setState(() {}); // Multilanguage package update
return _inst;
}
// Get the language package
static Future getLanguageJson() async {
if(! _hasConfigLocale) { _isLocale = (await LocalStorage.get('isLocale')) = ='false' ? false : true;
}
Locale _tmpLocale = _inst._locale;
String jsonLang;
String lang = ConfigLanguage.mapLanguage[_tmpLocale.toString()] ??
_tmpLocale.toString();
if (_isLocale) {
try {
print('Language package path: $_localePath/$lang.json');
jsonLang = await rootBundle.loadString('$_localePath/$lang.json');
// print(${json.decode(jsonLang)}');
} catch (e) {
print('Multilingual local path: $_localePath/$lang.json');
print('Multilingual local load path does not exist, load default language data :$e');
_inst._locale = Locale.fromSubtags(
languageCode: ConfigLanguage.defaultLanguage['language_code'],
scriptCode: ConfigLanguage.defaultLanguage['script_code']);
_tmpLocale = _inst._locale;
lang = ConfigLanguage.mapLanguage[_tmpLocale.toString()] ??
_tmpLocale.toString();
jsonLang = await rootBundle.loadString('$_localePath/$lang.json'); }}else {
try {
print('Language package path: $_I18nHost/$lang.json');
jsonLang = (await Http.get(url: '$_I18nHost/$lang.json')).toString();
// print(${(json.decode(jsonLang))}');
} catch (e) {
print('Multilingual platform path: $_I18nHost/$lang.json');
print('Multilingual platform loading path does not exist, load default language data: $e');
_inst._locale = Locale.fromSubtags(
languageCode: ConfigLanguage.defaultLanguage['language_code'],
scriptCode: ConfigLanguage.defaultLanguage['script_code']);
_tmpLocale = _inst._locale;
lang = ConfigLanguage.mapLanguage[_tmpLocale.toString()] ??
_tmpLocale.toString();
jsonLang = (await Http.get(url: '$_I18nHost/$lang.json')).toString();
}
}
_jsonLanguage['$_tmpLocale'] = json.decode(jsonLang.toString());
print('Whether to load the local language: $_isLocale');
print(
Get the language information for the language pack:${_inst._locale}, $lang, $_tmpLocale, ${_tmpLocale.languageCode}.${_tmpLocale.scriptCode}');
print("Multilanguage loaded data: $_jsonLanguage");
}
// Change whether to load local multilanguage
static void changeIsLocale(isLocale) async {
_isLocale = isLocale;
LocalStorage.set('isLocale', isLocale.toString());
init(_inst._locale);
}
// Switch languages
static void changeLanguage([Locale locale]) {
if (locale == null || locale.languageCode == null) {
print('Modify language language code cannot be null');
locale = Locale.fromSubtags(
languageCode: ConfigLanguage.defaultLanguage['language_code'],
scriptCode: ConfigLanguage.defaultLanguage['script_code']);
}
if(locale.scriptCode ! =null) {
_localeLang = '${locale.languageCode}-${locale.scriptCode}';
} else {
_localeLang = '${locale.languageCode}';
}
LocalStorage.set('lang', _localeLang);
init(Locale.fromSubtags(
languageCode: locale.languageCode,
scriptCode: locale.scriptCode)); // Get the corresponding internationalization file according to the language
}
static String $t(String key) {
Locale _tmpLocale = _inst == null
? Locale.fromSubtags(
languageCode: ConfigLanguage.defaultLanguage['language_code'],
scriptCode: ConfigLanguage.defaultLanguage['script_code'])
: _inst._locale;
var _array = key.split('. ');
var _dict = _jsonLanguage['$_tmpLocale']???? {};var retValue = ' ';
try {
_array.forEach((item) {
if(! _dict.containsKey(item) || _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 ?? ' '; }}Copy the code
The last
Welcome more friends learning about flutter to join QQ group Flutter UI: 798874340
Stay tuned to github: YYDev
The author