import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.script.Bindings; import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; import java.util.stream.Collectors; import java.util.stream.IntStream; public class LanguageFileCompare { private static Logger log = LoggerFactory.getLogger(LanguageFileCompare.class); public static void main(String[] args) { if (args.length > 0) { Path originPath = Paths.get(args[0]); JsonNode twJson = getJsonNode(originPath); if (twJson != null) { Set originSet = new HashSet<>(); addKeys("", twJson, originSet, new ArrayList<>()); IntStream.range(1, args.length) .forEach(i -> findMissingKeys(Paths.get(args[i]), originSet)); } } checkProperties(); } private static JsonNode getJsonNode(Path path) { String ext = path.getFileName().toString(); try { ObjectMapper objectMapper = new ObjectMapper(); if (ext.endsWith(".json")) { /* CHM、HRB */ return objectMapper.readTree(new String(Files.readAllBytes(path))); } else if (ext.endsWith(".js")) { /* CHMB use js file to translate */ ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); ScriptEngine engine = scriptEngineManager.getEngineByName("Nashorn"); engine.eval(new FileReader(path.toFile())); Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); return objectMapper.valueToTree(bindings.get("local")); } } catch (Exception e) { log.error("{} is not exists or file not correct.", path.getFileName(), e); System.exit(1); } return null; } private static void addKeys( String currentPath, JsonNode jsonNode, Set set, List suffix) { if (jsonNode.isObject()) { ObjectNode objectNode = (ObjectNode) jsonNode; Iterator> iter = objectNode.fields(); String pathPrefix = currentPath.isEmpty() ? "" : currentPath + "-"; while (iter.hasNext()) { Map.Entry entry = iter.next(); addKeys(pathPrefix + entry.getKey(), entry.getValue(), set, suffix); } } else if (jsonNode.isValueNode()) { StringBuilder sb = new StringBuilder(currentPath); if (currentPath.contains("-")) { for (Integer suffix1 : suffix) { sb.append("-").append(suffix1); } } set.add(sb.toString()); } } private static void findMissingKeys(Path targetPath, Set originSet) { if (!targetPath.toFile().exists()) return; Set targetSet = new HashSet<>(); JsonNode json = getJsonNode(targetPath); if (json == null) return; addKeys("", json, targetSet, new ArrayList<>()); Set missingKey = originSet .parallelStream() .filter(key -> !targetSet.contains(key)) .collect(Collectors.toSet()); if (!missingKey.isEmpty()) { log.error( "Missing Key on {} \nMissing Keys: {}", targetPath.getFileName(), missingKey.stream().sorted().collect(Collectors.toList())); System.exit(1); } } private static void checkProperties() { String path = "./src/main/resources/i18n/"; String extension = ".properties"; Map> map = Arrays.stream( Optional.ofNullable( Paths.get(path).toFile().list((dir, name) -> name.endsWith(extension))) .orElse(new String[0])) .map(s -> s.split(extension)[0]) .collect( Collectors.groupingBy( filename -> filename.split("_")[0], Collectors.mapping(l -> path + l + extension, Collectors.toList()))); for (Map.Entry> entry : map.entrySet()) { List twList = entry .getValue() .stream() .filter(fileName -> fileName.contains("zh_TW")) .collect(Collectors.toList()); List otherList = entry .getValue() .stream() .filter(fileName -> !fileName.contains("zh_TW")) .collect(Collectors.toList()); if (twList.isEmpty() || otherList.isEmpty()) continue; try { Set originKeySet = getKeys(twList.get(0)); for (String target : otherList) { Set targetKeySet = getKeys(target); Set missingSet = originKeySet .parallelStream() .filter(k -> !targetKeySet.contains(k)) .collect(Collectors.toSet()); if (!missingSet.isEmpty()) { log.error( "Missing Key on {} \nMissing Keys: {}", Paths.get(target).getFileName(), missingSet); System.exit(1); } } } catch (Exception e) { log.error("check i18n properties error.", e); System.exit(1); } } } private static Set getKeys(String fileName) throws IOException { Properties properties = new Properties(); properties.load(new FileInputStream(fileName)); return new HashSet(Collections.list(properties.propertyNames())); } }