在app文字语种 上,公司App主要针对国外用户,但同时还得兼顾国内的用户。

对于flutter来说,主要有两种实现方式,但是基本思想是一样的:都是根据App运行环境的语种,加载(我使用的本地加载)不同的静态资源,再进行渲染。

第一种方式利用 shared_preferences

主要记录第一种持久化存储的方案,因为后期的开发中还会使用到 sqlite

配置:

flutter已经提供国际化多语言,我们只需要配置好,然后使用就可以了。

1,准备两个语言版本的 json 文件:

// xlfd_zh.json
{
    "title": "我是小李飞刀"
}
// xlfd_en.json
{
    "title": "i am xlfd"
}

在pubspec.yaml配置assets:

flutter:

  uses-material-design: true

  assets:
    - lang/xlfd_en.json
    - lang/xlfd_zh.json

2,引入依赖 --- pubspec.yaml

flutter_localizations:flutter内置实现本地化的库;

shared_preferences:flutter插件,对android(SharedPreferences)和ios(NSUserDefaults)的存储进行了封装,可实现键值对存取;

flutter_localizations:
    sdk: flutter
  shared_preferences: ^0.5.3+4

flutter 设置 compileSdkVersion_flutter

ps:记得运行 flutter pub get

关键的两点是:如何拿到json文件的内容,并且根据系统语言加载对应的jason内容;如何监测系统语言的变化(用户在设置里切换语言),并且知道当前系统是何种语言;

3,监测系统语言的变化;获取当前系统是何种语言

flutter 设置 compileSdkVersion_ide_02

根级 Widget MaterialApp 中有一个配置项 localeResolutionCallback,值是一个回调,在App打开或者语言配置发生变化(在手机的设置里更改语言,app代码更改等)的时候会触发这个回调,入参两个参数 deviceLocale supportedLocales;前者会入参一个携带语言信息的Locale值,后者包含我们后面即将设置的语言支持种类

flutter 设置 compileSdkVersion_json_03

然后新建一个trahslations.dart文件:

import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show  rootBundle;
import 'package:shared_preferences/shared_preferences.dart';
/// 自定义的Translations类
class Translations {
	Translations(Locale locale) {
		this.locale = locale;
		_localizedValues = null;
	}

	Locale locale;
	static Map<dynamic, dynamic> _localizedValues;

	static Translations of(BuildContext context){
		return Localizations.of<Translations>(context, Translations);
	}

	String text(String key) {
		if(_localizedValues==null) {
			return "json文件无内容或获取内容失败";
		}
		return _localizedValues[key] ?? '**找不到 $key 对应的值**';
	}

	static Future<Translations> load(Locale locale) async {
		SharedPreferences sp = await SharedPreferences.getInstance();
        // 取出存储中的语种"lang"
		String lang =  sp.get("lang") == null ? "zh" : sp.get("lang");
		print('配置中存储的语言:$lang');
		Translations translations = new Translations(locale);
        // 读取json,格式化---此处注意层级关系
		String jsonContent = await rootBundle.loadString("lang/xlfd_$lang.json");
		_localizedValues = json.decode(jsonContent);
		applic.shouldReload = false;
		return translations;
	}

	get currentLanguage => locale.languageCode;
}

/// 自定义的localization代表,它的作用是在验证支持的语言前,初始化我们的自定义Translations类
class TranslationsDelegate extends LocalizationsDelegate<Translations> {
	const TranslationsDelegate();

	/// 改这里是为了不硬编码支持的语言
	@override
	bool isSupported(Locale locale) => applic.supportedLanguages.contains(locale.languageCode);

	@override
	Future<Translations> load(Locale locale)=> Translations.load(locale);

	@override
	bool shouldReload(TranslationsDelegate old) => false;
}

/// Delegate类的实现,每次选择一种新的语言时,强制初始化一个新的Translations类
class SpecificLocalizationDelegate extends LocalizationsDelegate<Translations> {
	final Locale overriddenLocale;

	const SpecificLocalizationDelegate(this.overriddenLocale);

	@override
	bool isSupported(Locale locale) => overriddenLocale != null;

	@override
	Future<Translations> load(Locale locale) => Translations.load(overriddenLocale);

	@override
	bool shouldReload(LocalizationsDelegate<Translations> old) {

		return applic.shouldReload??false;
	}
}

typedef void LocaleChangeCallback(Locale locale);

class APPLIC {
	// 支持的语言列表
	final List<String> supportedLanguages = ['en','zh'];

	// 支持的Locales列表
	Iterable<Locale> supportedLocales() => supportedLanguages.map<Locale>((lang) => new Locale(lang, ''));

	// 当语言改变时调用的方法
	LocaleChangeCallback onLocaleChanged;

	bool shouldReload;

	static final APPLIC _applic = new APPLIC._internal();

	factory APPLIC(){
		return _applic;
	}

	APPLIC._internal();
}

APPLIC applic = new APPLIC();

准备工作基本完毕,现在进行配置:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

/// 国际化依赖
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'lang/trahslations.dart';
/// 国际化依赖

import 'pages/Routes.dart';
import 'pages/quotePages.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  MyApp({Key key}) : super(key: key);

  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  SpecificLocalizationDelegate _localeOverrideDelegate;

  onLocaleChange(Locale locale) async {
    print('onLocaleChange--触发');
    // 实例化SharedPreferences以供存储
    SharedPreferences sp = await SharedPreferences.getInstance();
    // 更新语言配置 --- key为"lang",value为locale.languageCode
    await sp.setString("lang", locale.languageCode);
    // 根据语言更新_localeOverrideDelegate,以供给localizationsDelegates
    setState(() {
      _localeOverrideDelegate = new SpecificLocalizationDelegate(locale);
    });
  }

  @override
  void initState() {
    super.initState();
    _localeOverrideDelegate = new SpecificLocalizationDelegate(null);
    applic.onLocaleChanged = onLocaleChange;
  }

  // App 根级 widget
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
          home: Sign_inPage(), // App 首页
          routes: routesMap(), // routes注册
          initialRoute: 'sign_in', // 在注册了routes的前提下,指定一个route作为首页 --- 级别高于 home
          // 国际化配置
          localizationsDelegates: [
            _localeOverrideDelegate,
            const TranslationsDelegate(),
            GlobalMaterialLocalizations.delegate,
            GlobalWidgetsLocalizations.delegate,
          ],
          supportedLocales: applic.supportedLocales(), // 支持的语种
          localeResolutionCallback: (deviceLocale, supportedLocales) {
            String langStr = deviceLocale.toString();
            bool isCN = false;
            if (langStr.isNotEmpty) {isCN = deviceLocale.toString().toLowerCase().indexOf('zh', 0) > -1;}
            String langCode = 'en';
            if (isCN) {langCode = 'zh';}
            applic.shouldReload = true;
            applic.onLocaleChanged(new Locale(langCode,''));
            return;
          }
    );
  }
}

4,读取 json 文件,并且根据系统语言(第3步提供)加载对应的 json 文件

在第三步中的trahslations.dart文件内:

flutter 设置 compileSdkVersion_flutter_04

根据lang动态加载不同的json文件;

 

使用

flutter 设置 compileSdkVersion_flutter_05

String _lang(String key) {
    return Translations.of(context).text(key);
}

_lang('title');

主动变更语言:

flutter 设置 compileSdkVersion_ide_06

添加新的语言

首先在 trahslations.dart 文件中的 APPLIC 类里的 supportedLanguages 添加上要增加的语言code:

flutter 设置 compileSdkVersion_ide_07

然后添加json文件:

// xlfd_xlfd.json
{
    "title": "俺是小李飞刀"
}
flutter:

  uses-material-design: true

  assets:
    - lang/xlfd_en.json
    - lang/xlfd_zh.json
    - lang/xlfd_xlfd.json

测试:

flutter 设置 compileSdkVersion_国际化_08

效果:

flutter 设置 compileSdkVersion_json_09