前言
在过去的开发中往往不会过多考虑多语言切换功能,但是随着功能不断的迭代,用户需求不断更新,当我们要实现多语言切换的需求时,发现需要修改的地方数之不尽,难度系数非常大,往往会考虑成本过高而最终放弃,基于此我们将在项目初期保留多语言切换功能,并且支持多语言扩展,以满足不同的用户需求
方案一:Intl实现多语言切换
安装 Intl 插件
安装完成再重启AndroidStudio后生效
添加项目依赖
flutter_localizations:
sdk: flutter
自动生成目录
点击Tools->Flutter Intl -> Initialze for the Project
此时会自动在pubspec.yaml文件中添加 flutter_intl: enabled: true,并且生成 lib->generated-> intl 和 l10n 目录以及相对应的文件,请勿手动修改
添加语言支持
Tools -> Flutter Intl -> Add locale
选择对应语言,例如zh,en。如果有繁体支持,港台分别为zh_TW/zh_HK.
选定后,会在l10n文件夹下自动创建对应文件,例如 intl_en.arb/intl_zh.arb
项目代码应用
编辑arb文件
intl_en.arb
{
"test" : "测试"
}
intl_zh.arb
{
"test" : "Test"
}
中英文切换
@override
Widget build(BuildContext context) {
return MaterialApp(
// 切换中英文
locale: const Locale('zh', ''),
// locale: const Locale('en', ''),
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate
],
supportedLocales: [
const Locale('zh', ''),
...S.delegate.supportedLocales
],
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: const MyHomePage(title: 'Flutter Demo Home Page'));
}
调用字符串
S.of(context).test
或者
S.current.test
以上中英文切换随着系统语言的切换而切换,我们也可以不随着系统切换,而是在我们自己的应用内通过用户手动进行切换
手动多语言切换
/// 字符串资源
class StringLocale extends ChangeNotifier {
Locale get value => _locale;
Locale _locale = const Locale('zh', 'HK');
// 中文(默认)
static const String languageCN = 'zh_Hk';
// 英文
static const String languageEN = 'en_US';
/// 初始化
init() {
String language =
SPUtil().getString(SpKey.appLanguage, defaultValue: languageCN);
if (language == languageCN) {
// 中文
_locale = const Locale('zh', 'HK');
} else if (language == languageEN) {
// 英文
_locale = const Locale('en', 'US');
}
}
/// 设置语言
setLocale(Locale locale, String language) {
_locale = locale;
SPUtil().put(SpKey.appLanguage, language);
notifyListeners();
}
/// 获取实例
static S create() {
return S.current;
}
}
初始化
@override
Widget build(BuildContext context) {
// 屏幕适配,设计稿中设备的屏幕尺寸,单位dp (375x667)
return ScreenUtilInit(
designSize: Size(375, 667),
builder: () => Consumer<String591>(
builder: (context, locale, child) {
locale.init();
return MaterialApp(
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate
],
locale: locale.value,
supportedLocales: const [
Locale('zh', 'HK'),
Locale('en', 'US'),
],
home: SplashPage(),
);
},
));
}
切换成中文
Provider.of<StringLocale>(context, listen: false)
.setLocale(const Locale('zh', 'HK'), StringLocale.languageCN);
切换成英文
Provider.of<StringLocale>(context, listen: false)
.setLocale(const Locale('en', 'US'), StringLocale.languageEN);
调用的方式
String591.create().
方案二:自定义实现多语言切换
代码实现
字符串基类
/// 字符串基类
abstract class BaseString {
String get home;
String get list;
String get more;
}
字符串中文类
/// 字符串-中文类
class CNString extends BaseString {
@override
String get home => '首页';
@override
String get list => '列表';
@override
String get more => '更多';
}
字符串英文类
/// 字符串英文类
class ENString extends BaseString {
@override
String get home => 'Home';
@override
String get list => 'List';
@override
String get more => 'More';
}
代码使用
多语言切换
实现方案一:
/// 字符串资源
class StringModel {
// 中文
static const String languageCN = 'CN';
// 英文
static const String languageEN = 'EN';
// 中文字符串对象
static final BaseString cnString = CNString();
// 英文字符串对象
static final BaseString enString = ENString();
/// 切换语言(cn:中文版; en:英文版)
static changeLanguage(String language) {
if (null != language && language.isNotEmpty) {
SpUtil().put(SpKey.SP_APP_LANGUAGE, language);
}
}
/// 获取语言类型(cn:中文版; en:英文版)
static String getLanguageType() {
return SpUtil().getString(SpKey.SP_APP_LANGUAGE, defaultValue: languageCN);
}
/// 工厂模式,考虑多语言扩展性,字符串复用性等等
static BaseString create() {
String language =
SpUtil().getString(SpKey.SP_APP_LANGUAGE, defaultValue: languageCN);
if (language == languageEN) {
// 英文版
return enString;
} else {
// 中文版
return cnString;
}
}
/// 返回一个字符串(弃用,该方法不利于后续扩展和维护)
static getString({String cn = '', String en = ''}) {
String language =
SpUtil().getString(SpKey.SP_APP_LANGUAGE, defaultValue: languageCN);
if (language == languageEN) {
// 英文版
return en;
} else {
// 中文版
return cn;
}
}
}
实现方案二:
# 状态管理
# https://pub.dev/packages/provider/install
provider: ^6.0.1
// 程序入口
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => StringModel()),
],
child: const MyApp(),
),
);
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
/// 字符串资源
class StringModel extends ChangeNotifier {
// 中文
static const String languageCN = 'CN';
// 英文
static const String languageEN = 'EN';
late BaseString _baseString;
// BaseString get baseString => _baseString;
StringModel() {
String language =
SpUtil().getString(SpKey.appLanguage, defaultValue: languageCN);
if (language == languageEN) {
// 英文版
_baseString = ENString();
} else {
// 中文版
_baseString = CNString();
}
}
/// 多语言切换
void updateLanguage(String language) {
if (language == languageEN) {
// 英文版
_baseString = ENString();
} else {
// 中文版
_baseString = CNString();
}
SpUtil().put(SpKey.appLanguage, language);
notifyListeners();
}
/// 创造字符串对象
/// 通过Provider.of<T>(context)方法,可以在以Provider为根节点的子树中获取到T的对象
static BaseString create(BuildContext context, {bool? listen}) {
if (null == listen) {
return Provider.of<StringModel>(context)._baseString;
} else {
return Provider.of<StringModel>(context, listen: listen)._baseString;
}
}
}
字符串调用
// 第一种实现,重启app后生效:
StringModel.updateLanguage(language) // 切换语言
StringModel.create().home // 调用方法案例
// 第二种实现,直接生效:
Provider.of<StringModel>(context, listen: false).updateLanguage(language) // 切换语言
StringModel.create(context).home // 调用方法案例
总结
不论是使用第三方插件intl还是自定义实现,都能够满足多语言切换功能。它们将不同的语言文件进行区分隔离,有利于多语言切换的扩展和维护,并且在一定程度上提高了代码的可阅读性。