关于java:后端国际化二-使用AST完成中文的提取和过滤

45次阅读

共计 2699 个字符,预计需要花费 7 分钟才能阅读完成。

提取中文

本工具应用 org.eclipse.jdt.core 将 java 代码转换成 AST

  1. 将 java 代码转换成 AST 树

    def parser = new Parser()
    CompilationUnit result = parser.ast(content)
    Document document = new Document(src.text)
    def ast = result.getAST()
  2. 应用 Vistior 模式遍历所有字符串

    List<StringLiteral> visitChineseText(CompilationUnit result){var translateList = []
     result.accept(new ASTVisitor(){
         @Override
         boolean visit(StringLiteral node) {if(node.toString() =~ Config.DOUBLE_BYTE_REGEX){translateList.add(node)
             }
             return super.visit(node)
         }
     })
     return translateList
    }

过滤

原理:相熟 AST

以下是 logger.info("异样信息"+e) 的 AST

如果咱们须要过滤logger.info("异样信息"+e),咱们须要 lookup 到 MethodInvocation 节点,而后查看 MethodInvocation 的 expression 是否为 SimpleName 类型,且 getIdentifier() == “logger”

须要过滤的中文

kiwi 中实现的过滤器反对过滤以下中文:

  • 去除正文
  • 过滤 log 中的中文
  • 系统配置的中文
  • 参加业务逻辑的中文比方 “ 中文 ”.equsals(“ 中文 ”)
  • 正则匹配的中文字符(只蕴含标点)
  • 存在于注解中的中文
  • 存在于枚举的中文
  • 正文中增加了 kiwi-disable-method

过滤器实现

所有的过滤器实现了 Predicate<StringLiteral> 接口,用来判断中文是否过滤

罕用的过滤器有:

  1. 注解过滤器
boolean isInAnnotation(StringLiteral stringLiteral){
    def parent = stringLiteral.parent
    // 以 StringLiteral 节点向上查找,如果找到了注解,则返回 true
    while (parent != null && !(parent instanceof TypeDeclaration)) {if(parent instanceof Annotation){def memberValuePair = AstUtils.lookupUntilASTNode(stringLiteral, MemberValuePair.class)
            if(memberValuePair.isPresent()){return !shouldExclude(memberValuePair.get(), parent)
            }
            return true
        }
        parent = parent.parent
    }
    return false
}
  1. 常量过滤器
  2. 枚举过滤器

通常 Enum 里的中文无需翻译,也无奈替换,因为不能在初始化的时候调用办法

public enum RpFlagEnum {
    /**
     * 应酬
     */
    P("P","应酬"),

    /**
     * 应收
     */
    R("R","应收");
}
  def optMethod = AstUtils.lookupUntilASTNode(stringLiteral, EnumConstantDeclaration.class)
  if (optMethod.isPresent()) {return true}
  return false
  1. 日志过滤

过滤 log.info(“ 中文 ”)

        def optMethod = AstUtils.lookupUntilASTNode(stringLiteral, MethodInvocation.class)
        if(optMethod.isPresent()){def methodName = optMethod.get().getExpression()
            // log.info(xxx)
            if(methodName instanceof SimpleName){def simpleName = (SimpleName)methodName
                if(isLogInfo(simpleName.getIdentifier())){return true}
                // this.log.info(xxx)
            } else if(methodName instanceof  FieldAccess){def fieldAccess = (FieldAccess)methodName
                def fieldName = fieldAccess.getName()
                if(isLogInfo(fieldName.getIdentifier())){return true}
            }
        }
        return false
  1. Main 办法过滤
  2. I18n 办法过滤
  3. 正文中增加了 kiwi-disable-method

某些状况下咱们须要过滤的中文属于业务逻辑,然而代码无奈判断,须要增加正文跳过

/**
*
* kiwi-disable-method
*/
pubic String abc(){return "中文";}
    boolean hasMethodComment(StringLiteral stringLiteral) {
        def parent = stringLiteral.parent
        while (parent != null && !(parent instanceof TypeDeclaration)) {if(parent instanceof MethodDeclaration){def doc = parent.getJavadoc()
                return doc.toString().contains(methodComment)
            }
            parent = parent.parent
        }
        return false
    }
  1. 正则过滤器(正则匹配的中文字符(只蕴含标点))
  2. 参加业务逻辑的中文比方 “ 中文 ”.equsals(“ 中文 ”)
   boolean hasStringEquals(StringLiteral stringLiteral){def optMethod = AstUtils.lookupUntilASTNode(stringLiteral, MethodInvocation.class)
        if(optMethod.isPresent()){def method = optMethod.get()
            if(method.name.identifier == "equals"){return true}
        }
        return false
    }

正文完
 0