【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. 字体行高需要手动调整,否则一句话可能无法垂直对齐
相关推荐
sun_weitao20 分钟前
Flutter路由动画Hero函数的使用
java·服务器·flutter
ChinaDragonDreamer2 小时前
Flutter:使用FVM安装多个Flutter SDK 版本和使用教程
flutter·鸿蒙
GY-932 小时前
Flutter项目适配鸿蒙
flutter·harmonyos
sun_weitao2 小时前
Flutter使用BorderRadiusTween实现由矩形变成圆形的动画
flutter
2401_897444641 天前
用AI技术提升Flutter开发效率:ScriptEcho的力量
前端·人工智能·flutter
程序猿000001号1 天前
Vue.js 中父组件与子组件通信指南
前端·vue.js·flutter
Bonway_Huang1 天前
Mac 端 VSCode Flutter 快捷键大全
vscode·flutter·macos
lichong9511 天前
【Flutter&Dart】tolyui_feedback组件例子效果(23 /100)
android·flutter·api·postman·tooltip·smartapi
lichong9512 天前
【Flutter&Dart】 listView.builder例子二(14 /100)
android·javascript·flutter·api·postman·postapi·foxapi