【Flutter多语言翻译】一句话翻译返回多个widget

dart 复制代码
/// [getTranslate]处理多语言结构,返回Widget
/// 示例讲解:
/// lib/l10n/app_zh.arb 和 lib/l10n/app_en.arb 文件中:
/// 1. 使用"{}"包裹占位符,用官方方法解析,AppLocalizations.of(context).wakeup('学习服务') 返回的是纯String,
/// 即:"唤醒学习服务"。
/// ```json
///   "wakeup": "唤醒{svcType}",
///   "@wakeup": {
///     "description": "唤醒学习服务",
///     "placeholders": {
///       "svcType": {
///         "type": "String",
///         "example": "学习服务"
///       }
///     }
///   },
/// ```
///
/// 2. 使用"<??>"包裹占位符,结合[getTranslate]解析,会将 String 切割为 List<String>
/// 以<??>"为切割点",
/// "doAction": "列举几个操作:<?action1?>和<?action2?>以及<?buyHint2?>,你看如何?",
/// 切割后示例:
/// ["列举几个操作:", "<?action1?>","和","<?action1?>","以及","<?buyHint2?>", ",你看如何?"]
///
/// ```dart
///   getTranslate(
///     text: AppLocalizations.of(context).doAction,
///     defaultTextStyle: TextStyle(color: Colors.blue), // "列举几个操作:","和","以及", ",你看如何?" 这些文字显示为Colors.blue
///     hightlightTextStyle: TextStyle(color: Colors.yellow), // <?action1?>的内容显示为Colors.yellow
///     keyValue: {
///       "action1": AppLocalizations.of(context).xxx, // 纯文字,使用hightlightTextStyle
///       "action2": TextButton(child: Text(AppLocalizations.of(context).xxx, textStyle: TextStyle(color: Colors.orange)), onPressed() {}), // TextButton自带交互,不使用hightlightTextStyle
///       "buyHint2": Text(
///         AppLocalizations.of(context).xxx, 
///         textStyle: TextStyle(color: Colors.green, hight:1, decoration: TextDecoration.underline),
///       ), // Text自带交互,不使用hightlightTextStyle
///     },
///   )
/// ```
/// 3. 一句话中,同时存在"{}"和"<??>"包裹占位符
/// [getTranslate]只切割"<??>","{}"包裹的部分由官方自动转为String传入;
/// 示例:
/// "doActionOnDemo": "列举几个操作:{action1}和<?action2?>,你看如何?",
/// "edit": "编辑"
/// ```dart
///   getTranslate(
///     text: AppLocalizations.of(context).doActionOnDemo('登录账号'),
///     defaultTextStyle: TextStyle(color: Colors.blue), // "列举几个操作:登录账号"(action1已被官方方法翻译为'登录账号'),显示为Colors.blue
///     hightlightTextStyle: TextStyle(color: Colors.yellow), // <?action1?>的内容显示为Colors.yellow
///     keyValue: {
///       "action2": AppLocalizations.of(context).edit, // "编辑",显示为Colors.yellow
///     },
///   )
/// ```
/// 参数说明
/// @param String [str]:
///   需要翻译的AppLocalizations.of(context).xxx
/// @param Map<String, String> [keyValue]:
///   keyValue的[key]需与"<??>"包裹的占位符一致,例如:"这是占位符示例<?demo?>",key就是"demo";
///   keyValue的[value]是<?demo?>翻译后的String值,或者是一个Widget;
/// @param TextStyle [defaultTextStyle] :
///   常规文字的样式
/// @param TextStyle [hightlightTextStyle] :
///   高亮文字的样式(仅当keyValue传入的value是String时生效,如果value传入的是Widget就不生效)
///
Widget getTranslate({
  required String str,
  required Map keyValue,
  TextStyle? defaultTextStyle,
  TextStyle? highlightTextStyle,
}) {
  /// "列举几个操作:{buyHint}和<?buyHint2?>,你看如何?",
  RegExp rExp = RegExp(r'<\?(.+?)\?>'); // 去匹配<??>中间的内容
  var lastIndex = 0;
  var result = rExp.allMatches(str);
  List<InlineSpan> widgetList = [];
  for (var match in result) {
    // 将匹配前的部分加入到结果中
    if (match.start > lastIndex) {
      var firstText = str.substring(lastIndex, match.start);
      widgetList.add(TextSpan(text: firstText, style: defaultTextStyle));
    }
    // 关键字替换
    String key = match.group(1) ?? ''; // key的匹配结果是'action1'/'action2'/'buyHint2'
    if (keyValue[key] != null) {
      if (keyValue[key] is String) {
        // 如果keyValue的value传入的是String文字,使用TextSpan设置高亮色
        widgetList.add(TextSpan(text: keyValue[key], style: highlightTextStyle));
      } else if (keyValue[key] is Widget) {
        // 如果keyValue的value传入的是Widget,使用WidgetSpan包裹Widget,样式需要外部写
        widgetList.add(WidgetSpan(child: keyValue[key]));
      }
    }

    // 更新lastIndex为当前匹配项的结束位置
    lastIndex = match.end;
  }
  // 将剩余的非匹配部分添加到结果中
  if (lastIndex < str.length) {
    var lastText = str.substring(lastIndex);
    widgetList.add(TextSpan(text: lastText, style: defaultTextStyle));
  }

  return Text.rich(TextSpan(children: widgetList));
}

封装成一个TranslateWidget控件

dart 复制代码
class TranslateWidget extends StatelessWidget{
    const TranslateWidget({
		super.key,
		required String str,
		this.keyValue,
		this.defaultTextStyle,
  		this.highlightTextStyle,
	});
	final String str,
  	final Map keyValue,
    final TextStyle? defaultTextStyle,
    final TextStyle? highlightTextStyle,

	@override
	Widget build(BuildContext context) {
		return getTranslate(
			str: str,
  			keyValue: keyValue,
  			defaultTextStyle: defaultTextStyle,
  			highlightTextStyle: highlightTextStyle,
		);
	}
}

运用TranslateWidget:

dart 复制代码
// zh.arb
{
	"demoSentence": "这是一个句子,首先展示第一个示例:{demo1},接着展示第二个示例:<?demo2?>,最后展示第三个示例:<?demo3?>",
	"@demo1": {
		"description": "这是一个句子,首先展示第一个示例:随意填写的原生示例1,接着展示第二个示例:<?demo2?>,最后展示第三个示例:<?demo3?>",
     	"placeholders": {
     	  	"demo1": {
      	  		"type": "String",
				"example": "随意填写的原生示例1"
			}
		}
 	},
	"demo1": "原生示例1",
	"demo2": "自定义示例2",
    "demo3": "自定义示例3"
}
dart 复制代码
// 某个widget中
Widget build (BuildContext context) {
	var lang = AppLocalizations.of(context);
	return Container(
	    padding: const EdgeInsets.all(10),
    	child: TranslateWidget(
			str: lang!.demoSentence(lang.demo1),
			keyValue: {
				"demo2": Text(lang!.demo2, textStyle: TextStyle(color: Colors.red,backgroundColor: Colors.pink)),
				"demo3": lang!.demo3
			},
			defaultTextStyle: TextStyle(color: Colors.black),
			highlightTextStyle: TextStyle(backgroundColor: Colors.yellow),
		),
	),
}

显示效果大概如下 ↓↓↓ :


这是一个句子,首先展示第一个示例:原生示例1,接着展示第二个示例:自定义示例2,最后展示第三个示例:自定义示例3


文章从 TranslateWidget 控件开始,是根据思路手打出来的,没有运行过,可能有疏漏导致报错。

  1. <??> 是作者认为比较舒服的标记,标记可由读者自行定义
  2. getTranslate 方法,需要搭配多语言的arb文件一起使用。
  3. 字体行高需要手动调整,否则一句话可能无法垂直对齐
相关推荐
Zsnoin能8 小时前
flutter国际化、主题配置、视频播放器UI、扫码功能、水波纹问题
flutter
早起的年轻人8 小时前
Flutter CupertinoNavigationBar iOS 风格导航栏的组件
flutter·ios
HappyAcmen8 小时前
关于Flutter前端面试题及其答案解析
前端·flutter
coooliang17 小时前
Flutter 中的单例模式
javascript·flutter·单例模式
coooliang17 小时前
Flutter项目中设置安卓启动页
android·flutter
JIngles12317 小时前
flutter将utf-8编码的字节序列转换为中英文字符串
java·javascript·flutter
B.-20 小时前
在 Flutter 中实现文件读写
开发语言·学习·flutter·android studio·xcode
freflying11191 天前
使用jenkins构建Android+Flutter项目依赖自动升级带来兼容性问题及Jenkins构建速度慢问题解决
android·flutter·jenkins
机器瓦力1 天前
Flutter应用开发:对象存储管理图片
flutter
江上清风山间明月2 天前
Flutter最简单的路由管理方式Navigator
android·flutter·ios·路由·页面管理·navigator