乐趣区

关于java:后端国际化三-使用AST完成中文转换和替换

前言

在实现中文的提取和过滤之后,咱们须要对中文节点进行转换、翻译、替换。

文案转换

文案转换通常有一下几个状况

一般文案

比方 ” 保留胜利 ”,间接替换成对应的 code 即可

拼接的文案

"用户" + user.name + "不能为空",会做占位符转换, 合并成 "用户{0} 不能为空", 而后替换成对应的 code

注解中的文案

比方"用户不能为空",须要替换成成对应的{code},code 两边须要退出{},以符合要求。

节点替换

一般文案

"保留胜利"
替换为
I18nUtils.getMessage("save_succeeded")

拼接文案

"用户名" + user.name + "不能为空"
替换为
I18nUtils.getMessage("user_name_not_empty", new Object[]{user.name})

注解中的文案

@NotNull(message = "'type' 不能为空 ")
替换为
@NotNull(message ="{type_cannot_be_empty}")

字段中的字符串

private static String abc = "你好"
替换为

private String getAbc(){return I18nUtils.getMessage("hello")
}

MessageFormat.format 中的文案

MessageFormat.format("用户名 {0} 不能为空", user.name)
替换为
I18nUtils.getMessage("user_name_not_empty", new Object[]{user.name})

替换原理

所谓替换,就是解析相应的 AST 树并转为指标树

一般文案 AST 树结构

MethodInvocation getI18nCall(List<ASTNode> args){def methodInvocation = ast.newMethodInvocation()
    methodInvocation.setExpression(ast.newSimpleName(Config.getI18nClass()))
    methodInvocation.name = ast.newSimpleName("getMessage")
    methodInvocation.arguments().addAll(args)
    methodInvocation
}

简单文案节点结构

源 AST 树(MessageFormat.format(“{0}”, row))

指标 AST 树(I18nUtils.getMessage(“{0}”, new Object[]{ row}))

void replaceMessageFormatWithI18n(MethodInvocation methodInvocation, StringLiteral stringLiteral){def args = []
  // 提取 MessageFormat.format 中的第一个中文
  StringLiteral code = ASTNode.copySubtree(methodInvocation.getAST(), stringLiteral)
  // 翻译并替换 code
  translateKey(code)

  // 获取 MessageFormat.format 残余的参数
  List<ASTNode> retainExp = methodInvocation.arguments().subList(1, methodInvocation.arguments().size())
      .collect({ASTNode.copySubtree(methodInvocation.getAST(), (ASTNode)it) })

  args.add(code)
  def array = ast.newArrayCreation()
  args.add(array)
  // 结构 new Object 节点
  array.setType(ast.newArrayType(ast.newSimpleType(ast.newSimpleName("Object"))))
  def arrayInitializer = ast.newArrayInitializer()
  // 将残余的参数全副退出到 new Object 节点
  arrayInitializer.expressions().addAll(retainExp)
  array.setInitializer(arrayInitializer)

  // 转换为 I18nUtils.getMessage 模式
  convertStringLiteral(args, methodInvocation)
}
退出移动版