update timi-lang

This commit is contained in:
Timi
2025-12-08 16:53:38 +08:00
parent 59b0153f3e
commit bc2c920705
8 changed files with 32 additions and 442 deletions

View File

@ -40,13 +40,13 @@ public class TimiServerAPI implements OS.FileSystem, ApplicationContextAware {
TimiServerAPI.applicationContext = applicationContext; TimiServerAPI.applicationContext = applicationContext;
} }
public static Language getUserLanguage() { public static Language.Enum getUserLanguage() {
Language userLanguage = TimiSpring.getLanguage(); Language.Enum userLanguage = TimiSpring.getLanguage();
Environment env = applicationContext.getBean(Environment.class); Environment env = applicationContext.getBean(Environment.class);
if (env.containsProperty(DEV_LANG_CONFIG)) { if (env.containsProperty(DEV_LANG_CONFIG)) {
String property = env.getProperty(DEV_LANG_CONFIG); String property = env.getProperty(DEV_LANG_CONFIG);
if (TimiJava.isNotEmpty(property)) { if (TimiJava.isNotEmpty(property)) {
userLanguage = Ref.toType(Language.class, property); userLanguage = Ref.toType(Language.Enum.class, property);
} }
} }
return userLanguage; return userLanguage;

View File

@ -1,14 +1,14 @@
package com.imyeyu.api.modules.common.entity; package com.imyeyu.api.modules.common.entity;
import com.imyeyu.java.bean.timi.TimiCode; import com.imyeyu.java.bean.Language;
import com.imyeyu.java.bean.timi.TimiException; import com.imyeyu.spring.entity.Creatable;
import com.imyeyu.java.ref.Ref; import com.imyeyu.spring.entity.Deletable;
import com.imyeyu.api.TimiServerAPI; import com.imyeyu.spring.entity.IDEntity;
import com.imyeyu.spring.entity.Entity; import com.imyeyu.spring.entity.Updatable;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.lang.reflect.Field; import java.io.Serializable;
/** /**
* @author 夜雨 * @author 夜雨
@ -16,52 +16,13 @@ import java.lang.reflect.Field;
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class Multilingual extends Entity { public class Multilingual extends Language implements Serializable, IDEntity<Long>, Creatable, Updatable, Deletable {
protected String key; protected Long id;
protected String zhCN; protected Long createdAt;
protected String zhTW; protected Long updatedAt;
protected String enUS; protected Long deletedAt;
protected String ruRU;
protected String koKR;
protected String jaJP;
protected String deDE;
/** @return 根据用户环境获取语言值 */
public String getValue() {
try {
Field field = Ref.getField(getClass(), TimiServerAPI.getUserLanguage().toString().replace("_", ""));
if (field == null) {
throw new TimiException(TimiCode.RESULT_NULL).msgKey("TODO not support language");
}
return Ref.getFieldValue(this, field, String.class);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
/**
* 获取指定语言值
*
* @param language 指定语言
* @return 值
*/
public String getValue(com.imyeyu.java.bean.Language language) {
try {
Field field = Ref.getField(getClass(), language.toString().replace("_", ""));
if (field == null) {
throw new TimiException(TimiCode.RESULT_NULL).msgKey("TODO not support language");
}
return Ref.getFieldValue(this, field, String.class);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
} }

View File

@ -16,9 +16,9 @@ public interface MultilingualService extends UpdatableService<Multilingual> {
Long createIfNotExist(String key, String zhCN); Long createIfNotExist(String key, String zhCN);
String get(Language language, Long id); String get(Language.Enum language, Long id);
String getByKey(Language language, String key); String getByKey(Language.Enum language, String key);
List<Multilingual> listByNotTranslate(); List<Multilingual> listByNotTranslate();
} }

View File

@ -59,7 +59,7 @@ public class MultilingualServiceImplement extends AbstractEntityService<Multilin
} }
@Override @Override
public String get(Language language, Long id) { public String get(Language.Enum language, Long id) {
Multilingual result = redisLanguage.get(id); Multilingual result = redisLanguage.get(id);
if (result == null) { if (result == null) {
result = mapper.select(id); result = mapper.select(id);
@ -72,7 +72,7 @@ public class MultilingualServiceImplement extends AbstractEntityService<Multilin
} }
@Override @Override
public String getByKey(Language language, String key) { public String getByKey(Language.Enum language, String key) {
Long languageId = redisLanguageMap.get(key); Long languageId = redisLanguageMap.get(key);
if (languageId == null) { if (languageId == null) {
Multilingual result = mapper.selectByKey(key); Multilingual result = mapper.selectByKey(key);

View File

@ -50,16 +50,16 @@ public class MultilingualTranslateTask {
@AllArgsConstructor @AllArgsConstructor
public enum BaiduLanguage { public enum BaiduLanguage {
ZH(Language.zh_CN), ZH(Language.Enum.zh_CN),
EN(Language.en_US), EN(Language.Enum.en_US),
JP(Language.ja_JP), JP(Language.Enum.ja_JP),
KOR(Language.ko_KR), KOR(Language.Enum.ko_KR),
RU(Language.ru_RU), RU(Language.Enum.ru_RU),
DE(Language.de_DE), DE(Language.Enum.de_DE),
CHT(Language.zh_TW); CHT(Language.Enum.zh_TW);
/** 标准映射 */ /** 标准映射 */
final Language language; final Language.Enum language;
/** /**
* 获取排除语言列表 * 获取排除语言列表
@ -104,7 +104,7 @@ public class MultilingualTranslateTask {
Map<String, String> result = doTranslate(sb.toString(), languageList.get(j)); Map<String, String> result = doTranslate(sb.toString(), languageList.get(j));
for (Map.Entry<String, String> item : result.entrySet()) { for (Map.Entry<String, String> item : result.entrySet()) {
Multilingual multilingual = cnMap.get(item.getKey()); Multilingual multilingual = cnMap.get(item.getKey());
Language lang = languageList.get(j).language; Language.Enum lang = languageList.get(j).language;
String value = multilingual.getValue(lang); String value = multilingual.getValue(lang);
if (TimiJava.isEmpty(value)) { if (TimiJava.isEmpty(value)) {
Ref.setFieldValue(multilingual, lang.toString().replace("_", ""), item.getValue()); Ref.setFieldValue(multilingual, lang.toString().replace("_", ""), item.getValue());

View File

@ -12,7 +12,7 @@ import org.jcodec.api.NotSupportedException;
*/ */
public class RedisLanguage extends AbstractLanguageMapper { public class RedisLanguage extends AbstractLanguageMapper {
public RedisLanguage(Language language) { public RedisLanguage(Language.Enum language) {
super(language); super(language);
} }

View File

@ -1,10 +1,10 @@
package com.imyeyu.api.util; package com.imyeyu.api.util;
import jakarta.annotation.PostConstruct; import com.imyeyu.api.modules.common.service.MultilingualService;
import lombok.RequiredArgsConstructor;
import com.imyeyu.java.bean.Language; import com.imyeyu.java.bean.Language;
import com.imyeyu.lang.multi.Multilingual; import com.imyeyu.lang.multi.Multilingual;
import com.imyeyu.api.modules.common.service.MultilingualService; import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
@ -19,7 +19,7 @@ public class RedisMultilingual extends Multilingual {
@PostConstruct @PostConstruct
private void postConstruct() { private void postConstruct() {
Language[] languages = Language.values(); Language.Enum[] languages = Language.Enum.values();
for (int i = 0; i < languages.length; i++) { for (int i = 0; i < languages.length; i++) {
add(languages[i], new RedisLanguage(languages[i])); add(languages[i], new RedisLanguage(languages[i]));
} }

View File

@ -1,371 +0,0 @@
package test;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.imyeyu.io.IO;
import com.imyeyu.java.TimiJava;
import com.imyeyu.java.bean.CallbackArgReturn;
import com.imyeyu.java.bean.Language;
import com.imyeyu.java.bean.timi.TimiCode;
import com.imyeyu.java.bean.timi.TimiException;
import com.imyeyu.java.ref.Ref;
import com.imyeyu.network.FormMap;
import com.imyeyu.api.TimiServerAPI;
import com.imyeyu.api.modules.common.entity.Multilingual;
import com.imyeyu.api.modules.common.mapper.MultilingualMapper;
import com.imyeyu.utils.Digest;
import com.imyeyu.utils.Encoder;
import com.imyeyu.utils.Time;
import lombok.AllArgsConstructor;
import org.apache.hc.client5.http.fluent.Request;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@SpringBootTest(classes = TimiServerAPI.class)
@RunWith(SpringRunner.class)
public class SpringLang {
@Autowired
private MultilingualMapper mapper;
private static final String API = "http://api.fanyi.baidu.com/api/trans/vip/translate?";
@Test
public void temp() throws Exception {
List<Multilingual> multilinguals = mapper.selectByKeyLike(".exception.");
for (int i = 0; i < multilinguals.size(); i++) {
Multilingual item = multilinguals.get(i);
item.setKey(item.getKey().replaceAll("exception", "tips"));
mapper.update(item);
}
}
@Test
public void addLang() throws Exception {
Map<String, String> map = new HashMap<>();
for (Map.Entry<String, String> item : map.entrySet()) {
Multilingual exist = mapper.selectByKey(item.getKey());
if (exist != null) {
System.err.println("exist key: " + item.getKey());
continue;
}
Multilingual multilingual = new Multilingual();
multilingual.setKey(item.getKey());
multilingual.setZhCN(item.getValue());
multilingual.setCreatedAt(Time.now());
mapper.insert(multilingual);
}
}
@Test
public void addLang4File() throws Exception {
Properties properties = new Properties();
properties.load(IO.getInputStream(new File("newLang.properties")));
for (Map.Entry<Object, Object> item : properties.entrySet()) {
Multilingual exist = mapper.selectByKey(item.getKey().toString());
if (exist != null) {
System.err.println("exist key: " + item.getKey());
continue;
}
Multilingual multilingual = new Multilingual();
multilingual.setKey(item.getKey().toString());
multilingual.setZhCN(item.getValue().toString());
multilingual.setCreatedAt(Time.now());
mapper.insert(multilingual);
}
}
@Test
public void appendTranslateResult4Path() throws Exception {
String path = "";
// DB_KEY, FILE_KEY
Map<String, String> keyMap = new HashMap<>();
keyMap.put("", "");
for (Map.Entry<String, String> item : keyMap.entrySet()) {
Language[] languages = Language.values();
for (int i = 0; i < languages.length; i++) {
if (languages[i] == Language.zh_CN) {
continue;
}
Properties properties = new Properties();
File file = new File(path + "%s.lang".formatted(languages[i].toString()));
if (!file.exists()) {
System.err.println(languages[i] + " not exist");
continue;
}
properties.load(IO.getInputStream(file));
Multilingual multilingual = mapper.selectByKey(item.getKey());
String fieldName = languages[i].toString().replace("_", "");
Ref.setFieldValue(multilingual, fieldName, properties.getProperty(item.getValue()));
mapper.update(multilingual);
}
}
}
@Test
public void upper() {
List<Multilingual> list = mapper.list(0, 9999);
for (int i = 0; i < list.size(); i++) {
Multilingual multilingual = list.get(i);
multilingual.setEnUS(String.valueOf(multilingual.getEnUS().charAt(0)).toUpperCase() + multilingual.getEnUS().substring(1));
mapper.update(multilingual);
}
}
@Test
public void translate() throws Exception {
List<Multilingual> data = mapper.selectByNotTranslate();
Map<String, Multilingual> cnMap = new HashMap<>();
for (int i = 0; i < data.size(); i++) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < Math.min(data.size() - i, 20); j++, i++) {
Multilingual multilingual = data.get(i);
sb.append(multilingual.getZhCN()).append("\r\n");
cnMap.put(multilingual.getZhCN(), multilingual);
}
i--;
System.out.println("translate " + sb);
List<BaiduLanguage> languageList = BaiduLanguage.valuesWithout(BaiduLanguage.ZH);
for (int j = 0; j < languageList.size(); j++) {
Map<String, String> result = doTranslate(languageList.get(j), sb.toString());
for (Map.Entry<String, String> item : result.entrySet()) {
Multilingual multilingual = cnMap.get(item.getKey());
Language lang = languageList.get(j).language;
String value = multilingual.getValue(lang);
if (TimiJava.isEmpty(value)) {
Ref.setFieldValue(multilingual, lang.toString().replace("_", ""), item.getValue());
}
mapper.update(multilingual);
}
}
Thread.sleep(1000);
}
}
// 数据库查重
// SELECT * FROM multilingual WHERE zh_cn IN (SELECT zh_cn FROM multilingual GROUP BY zh_cn HAVING COUNT(zh_cn) > 1);
// SELECT * FROM multilingual WHERE key IN (SELECT key FROM multilingual GROUP BY key HAVING COUNT(key) > 1);
@Test
public void export() throws Exception {
Pattern compile = Pattern.compile("\\.(text|textArgs)\\(\"(.*?)\"");
File scanDir = new File("E:\\IDEAProject\\ForeverMC\\src");
File outDir = new File("E:\\IDEAProject\\ForeverMC\\src\\main\\resources\\lang");
// 排除键
// String[] excludePath = {};
String[] excludePath = {"E:\\IDEAProject\\timi-fx-ui\\src\\main\\resources\\lang\\timi-fx-ui"};
Set<String> excludeKeys = new HashSet<>();
if (excludePath.length != 0) {
for (int i = 0; i < excludePath.length; i++) {
InputStream is = IO.getInputStream(new File(excludePath[i] + "\\zh_CN.lang"));
Properties properties = new Properties();
properties.load(is);
Map<Object, Object> map = new HashMap<>(properties);
excludeKeys.addAll(map.keySet().stream().map(Object::toString).collect(Collectors.toSet()));
}
}
// 扫描文件获取键
List<File> files = IO.listFile(scanDir);
Set<String> keySet = new HashSet<>();
for (int i = 0; i < files.size(); i++) {
File file = files.get(i);
if (file.isDirectory()) {
continue;
}
if (!file.getName().endsWith(".java")) {
continue;
}
String fileData = IO.toString(file);
Matcher matcher = compile.matcher(fileData);
while (matcher.find()) {
String key = matcher.group(2);
if (!excludeKeys.contains(key)) {
keySet.add(key);
}
}
}
StringBuilder notFoundKey = new StringBuilder();
List<String> keyList = new ArrayList<>(keySet);
keyList.sort(Comparator.naturalOrder());
List<Multilingual> result = mapper.selectByKeyList(keyList);
{
List<String> deepQueryKeyList;
CallbackArgReturn<List<Multilingual>, List<String>> newKeyList = mList -> {
List<String> arr = new ArrayList<>();
for (int i = 0; i < mList.size(); i++) {
if (mList.get(i).getZhCN().startsWith("@")) {
String newKey = mList.get(i).getZhCN().substring(1);
if (!keyList.contains(newKey)) {
arr.add(newKey);
}
}
}
return arr;
};
deepQueryKeyList = newKeyList.handler(result);
do {
List<Multilingual> deepResult = new ArrayList<>();
for (int i = 0; i < deepQueryKeyList.size(); i++) {
Multilingual r = mapper.selectByKey(deepQueryKeyList.get(i));
if (r == null) {
notFoundKey.append("[deep]").append(deepQueryKeyList.get(i)).append('\n');
} else {
deepResult.add(r);
}
}
result.addAll(deepResult);
deepQueryKeyList = newKeyList.handler(deepResult);
} while (!deepQueryKeyList.isEmpty());
}
result.sort(Comparator.comparing(Multilingual::getKey));
Set<String> resultKey = result.stream().map(Multilingual::getKey).collect(Collectors.toSet());
for (String key : keyList) {
if (!resultKey.contains(key)) {
notFoundKey.append(key).append('\n');
}
}
if (!notFoundKey.isEmpty()) {
System.err.printf("not found key in db: %n------%n%s------%n", notFoundKey);
} else {
// 输出文件
Language[] languages = Language.values();
for (int i = 0; i < languages.length; i++) {
String fieldName = languages[i].toString().replace("_", "");
File file = IO.file(IO.fitPath(outDir.getAbsolutePath()) + languages[i] + ".lang");
StringBuilder sb = new StringBuilder();
for (int j = 0; j < result.size(); j++) {
String value = Ref.getFieldValue(result.get(j), fieldName, String.class).trim();
value = value.replaceAll("\n", "\\\\n\\\\\n");
sb.append(result.get(j).getKey()).append("=").append(value);
sb.append('\n');
}
IO.toFile(file, sb.toString());
}
System.out.println("write successful");
}
}
/**
* 文本翻译
*
* @param text 原文本
* @param to 目标语言
* @return Map&lt;原数据,翻译结果&gt;
* @throws Exception 翻译异常
*/
private synchronized Map<String, String> doTranslate(BaiduLanguage to, String text) throws Exception {
String random = String.valueOf(System.currentTimeMillis());
String appId = "20180920000210118";
String key = "MfI4Iu0go3541Ryx3f6K";
FormMap<String, Object> args = new FormMap<>();
args.put("q", text);
args.put("from", "ZH".toLowerCase());
args.put("to", to.toString().toLowerCase());
args.put("appid", appId);
args.put("salt", random);
args.put("sign", Digest.md5(appId + text + random + key));
String response = Request.post(API + Encoder.urlArgs(args)).bodyForm(args.build()).execute().returnContent().asString();
JsonObject jo = JsonParser.parseString(response).getAsJsonObject();
if (jo.has("error_code")) {
System.err.println(jo);
throw new TimiException(TimiCode.ERROR, jo.get("error_msg").getAsString());
}
JsonArray ja = jo.get("trans_result").getAsJsonArray();
JsonObject resultJO;
Map<String, String> result = new HashMap<>();
for (int i = 0; i < ja.size(); i++) {
resultJO = ja.get(i).getAsJsonObject();
result.put(resultJO.get("src").getAsString(), resultJO.get("dst").getAsString());
}
wait(200);
return result;
}
@AllArgsConstructor
public enum BaiduLanguage {
ZH(Language.zh_CN),
EN(Language.en_US),
JP(Language.ja_JP),
KOR(Language.ko_KR),
RU(Language.ru_RU),
DE(Language.de_DE),
CHT(Language.zh_TW);
/** 标准映射 */
final Language language;
/**
* 根据映射查找
*
* @param language 映射
* @return 枚举对象
*/
static BaiduLanguage fromMapping(Language language) {
for (BaiduLanguage type : BaiduLanguage.values()) {
if (type.language.toString().equalsIgnoreCase(language.toString())) {
return type;
}
}
return null;
}
/**
* 获取排除语言列表
*
* @param baiduLanguage 排除语言
* @return 语言列表
*/
static List<BaiduLanguage> valuesWithout(BaiduLanguage... baiduLanguage) {
Set<BaiduLanguage> outList = Set.of(baiduLanguage);
List<BaiduLanguage> result = new ArrayList<>();
BaiduLanguage[] values = values();
for (int i = 0; i < values.length; i++) {
if (!outList.contains(values[i])) {
result.add(values[i]);
}
}
return result;
}
}
}