杂谈 #Java脚本

因本人英语不好在使用Obsidian时,一些插件的设置英文多令人头痛。故有写一个的翻译插件介绍和设置脚本的想法。看到有些前人写的一下翻译方法,简直惨目忍睹。竟然要手动。这个应该写好到只需要一键就可以汉化的地步吗?

好吧。我承认这有些难度。翻译引擎就用有道的吧。我觉得它对专业名词的翻译准确度还是很高的。

  1. 提取main.js中需要的词句
  2. 使用有道API来翻译并生成对应的文件
  3. 使用Quicker的插件一键替换

这里不想详细写过程了,直接贴代码吧。以后有空再整合。

main.js处理代码:(用了FastJson里面的工具,需要导入)

import com.alibaba.fastjson.JSON;

import java.io.*;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern; /**
* @author ShuangLian
* @date 2022/7/4 1:07
*/
public class test {
public static void main(String[] args) throws IOException {
// 需要翻译的插件对应的main.js文件
File file = new File("C:\\Users\\91324\\Documents\\Projects\\IdeaProjects\\Test-demo\\src\\test\\java\\cn\\lian\\main.js");
System.out.println(file.getAbsolutePath());
FileInputStream stream = new FileInputStream(file);
InputStreamReader reader = new InputStreamReader(stream);
BufferedReader bufferedReader = new BufferedReader(reader);
LinkedList<String> list = new LinkedList<>();
String line;
while ((line = bufferedReader.readLine()) != null) {
// 匹配要翻译的部分
String s_setName = "setName\\([^\\)]+\\)";
String s_addOption = "addOption\\([^\\)]+\\)";
String s_setDesc = "setDesc\\([^\\)]+\\)*\"\\)";
String s_name = "name: \".*\",";
// 使用正则查找匹配
List<String> linkedList;
if ((linkedList = find(s_setName, line)).size() != 0) {
for (String s : linkedList) {
list.add(s.substring(9, s.length() - 2));
}
}
if ((linkedList = find(s_setDesc, line)).size() != 0) {
for (String s : linkedList) {
list.add(s.substring(9, s.length() - 2));
}
}
if ((linkedList = find(s_addOption, line)).size() != 0) {
for (String ss : linkedList) {
String substring = ss.substring(10, ss.length() - 1);
String[] split = substring.split(",");
for (String s : split) {
s = s.strip();
list.add(s.substring(1, s.length() - 1));
}
}
}
if ((linkedList = find(s_name, line)).size() != 0) {
for (String s : linkedList) {
list.add(s.substring(7, s.length() - 2));
}
}
}
System.out.println(list);
bufferedReader.close();
// 输出汉英对照.txt
File file1 = new File(".\\test2.txt");
FileOutputStream fileOutputStream = new FileOutputStream(file1);
// 指定输出文件编码为gbk,不知道为啥做替换插件的那个2b不使用UTF-8
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "gbk");
// OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
BufferedWriter writer = new BufferedWriter(outputStreamWriter);
for (String s : list) {
writer.append(s).append("\n");
String query = FanyiV3Demo.query(s);
String translation = JSON.parseObject(query).getJSONArray("translation").get(0).toString();
writer.append(translation).append("\n");
}
writer.flush();
}
public static List<String> find(String regex, String str) {
List<String> strings = new LinkedList<>();
Pattern p = Pattern.compile(regex);
Matcher matcher = p.matcher(str);
while (matcher.find()) {
String fundStr = str.substring(matcher.start(), matcher.end());
System.out.println(fundStr);
strings.add(fundStr);
}
return strings;
}
}

有道翻译Java SDK改装


/**
* @author ShuangLian
* @date 2022/7/4 3:49
*/ import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*; /**
* 由有道提供,直接调用query方法即可
* 返回示例:
* {
* "tSpeakUrl": "https://openapi.youdao.com/ttsapi?",
* "requestId": "afc14ed2-e6ca-49fe-8f8f-b36e6ff5bbaa",
* "query": "Preview on Hover for File Links",
* "translation": [
* "预览悬停文件链接"
* ],
* "errorCode": "0",
* "dict": {
* "url": "yddict://m.youdao.com/dict?le=eng&q=Preview+on+Hover+for+File+Links"
* },
* "webdict": {
* "url": "http://mobile.youdao.com/dict?le=eng&q=Preview+on+Hover+for+File+Links"
* },
* "l": "en2zh-CHS",
* "isWord": false,
* "speakUrl": "https://openapi.youdao.com/ttsapi?"
* }
*/
public class FanyiV3Demo { private static Logger logger = LoggerFactory.getLogger(FanyiV3Demo.class); private static final String YOUDAO_URL = "https://openapi.youdao.com/api";
// 去有道查看,这里不能直接用
private static final String APP_KEY = "1fcc4";
//
private static final String APP_SECRET = "LgA5Wxpm60KP7nyuGp"; public static void main(String[] args) throws IOException { Map<String, String> params = new HashMap<String, String>();
String q = "Decrease body font size";
String salt = String.valueOf(System.currentTimeMillis());
params.put("from", "en");
params.put("to", "zh-CHS");
params.put("signType", "v3");
String curtime = String.valueOf(System.currentTimeMillis() / 1000);
params.put("curtime", curtime);
String signStr = APP_KEY + truncate(q) + salt + curtime + APP_SECRET;
String sign = getDigest(signStr);
params.put("appKey", APP_KEY);
params.put("q", q);
params.put("salt", salt);
params.put("sign", sign);
params.put("vocabId", "您的用户词表ID");
/** 处理结果 */
requestForHttp(YOUDAO_URL, params);
} public static String query(String Str) throws IOException {
Map<String, String> params = new HashMap<String, String>();
String q = Str;
String salt = String.valueOf(System.currentTimeMillis());
params.put("from", "en");
params.put("to", "zh-CHS");
params.put("signType", "v3");
String curtime = String.valueOf(System.currentTimeMillis() / 1000);
params.put("curtime", curtime);
String signStr = APP_KEY + truncate(q) + salt + curtime + APP_SECRET;
String sign = getDigest(signStr);
params.put("appKey", APP_KEY);
params.put("q", q);
params.put("salt", salt);
params.put("sign", sign);
params.put("vocabId", "您的用户词表ID");
/** 处理结果 */
return requestForHttp(YOUDAO_URL, params);
} public static String requestForHttp(String url, Map<String, String> params) throws IOException { String json = null;
/** 创建HttpClient */
CloseableHttpClient httpClient = HttpClients.createDefault(); /** httpPost */
HttpPost httpPost = new HttpPost(url);
List<NameValuePair> paramsList = new ArrayList<NameValuePair>();
Iterator<Map.Entry<String, String>> it = params.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> en = it.next();
String key = en.getKey();
String value = en.getValue();
paramsList.add(new BasicNameValuePair(key, value));
}
httpPost.setEntity(new UrlEncodedFormEntity(paramsList, "UTF-8"));
CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
try {
Header[] contentType = httpResponse.getHeaders("Content-Type");
logger.info("Content-Type:" + contentType[0].getValue());
if ("audio/mp3".equals(contentType[0].getValue())) {
//如果响应是wav
HttpEntity httpEntity = httpResponse.getEntity();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
httpResponse.getEntity().writeTo(baos);
byte[] result = baos.toByteArray();
EntityUtils.consume(httpEntity);
if (result != null) {//合成成功
String file = "合成的音频存储路径" + System.currentTimeMillis() + ".mp3";
byte2File(result, file);
}
} else {
/** 响应不是音频流,直接显示结果 */
HttpEntity httpEntity = httpResponse.getEntity();
json = EntityUtils.toString(httpEntity, "UTF-8");
EntityUtils.consume(httpEntity);
logger.info(json);
System.out.println(json);
}
} finally {
try {
if (httpResponse != null) {
httpResponse.close();
}
} catch (IOException e) {
logger.info("## release resouce error ##" + e);
}
}
return json;
} /**
* 生成加密字段
*/
public static String getDigest(String string) {
if (string == null) {
return null;
}
char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
byte[] btInput = string.getBytes(StandardCharsets.UTF_8);
try {
MessageDigest mdInst = MessageDigest.getInstance("SHA-256");
mdInst.update(btInput);
byte[] md = mdInst.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (byte byte0 : md) {
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (NoSuchAlgorithmException e) {
return null;
}
} /**
* @param result 音频字节流
* @param file 存储路径
*/
private static void byte2File(byte[] result, String file) {
File audioFile = new File(file);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(audioFile);
fos.write(result); } catch (Exception e) {
logger.info(e.toString());
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} } public static String truncate(String q) {
if (q == null) {
return null;
}
int len = q.length();
String result;
return len <= 20 ? q : (q.substring(0, 10) + len + q.substring(len - 10, len));
}
}

还有一个问题:

Quicker插件只是替换功能,有可能会替换到正文的单词。这里应该是需要再使用正则匹配一遍。干脆改成只用java来处理吧。

记一次重复造轮子(Obsidian 插件设置说明汉化)的更多相关文章

  1. 答应我,用了这个jupyter插件,别再重复造轮子了

    1 简介 在使用Python.R等完成日常任务的过程中,可能会经常书写同样或模式相近的同一段代码,譬如每次使用matplotlib绘制图像的时候可以在开头添加下面两行代码来解决中文乱码等显示问题: p ...

  2. 避免重复造轮子的UI自动化测试框架开发

    一懒起来就好久没更新文章了,其实懒也还是因为忙,今年上半年的加班赶上了去年一年的加班,加班不息啊,好了吐槽完就写写一直打算继续的自动化开发 目前各种UI测试框架层出不穷,但是万变不离其宗,驱动PC浏览 ...

  3. GitHub Android 最火开源项目Top20 GitHub 上的开源项目不胜枚举,越来越多的开源项目正在迁移到GitHub平台上。基于不要重复造轮子的原则,了解当下比较流行的Android与iOS开源项目很是必要。利用这些项目,有时能够让你达到事半功倍的效果。

    1. ActionBarSherlock(推荐) ActionBarSherlock应该算得上是GitHub上最火的Android开源项目了,它是一个独立的库,通过一个API和主题,开发者就可以很方便 ...

  4. 第27篇 重复造轮子---模拟IIS服务器

    在写程序的时候,重复造轮子是程序员的一个大忌,很多人对重复造轮子持有反对的态度,但是我觉得这个造轮子的过程,是对于现有的知识的一个深入的探索的过程,虽然我们不可能把轮子造的那么的完善,对于现在有的东西 ...

  5. 重复造轮子,编写一个轻量级的异步写日志的实用工具类(LogAsyncWriter)

    一说到写日志,大家可能推荐一堆的开源日志框架,如:Log4Net.NLog,这些日志框架确实也不错,比较强大也比较灵活,但也正因为又强大又灵活,导致我们使用他们时需要引用一些DLL,同时还要学习各种用 ...

  6. Light libraries是一组通用的C基础库,目标是为减少重复造轮子而写(全部用POSIX C实现)

    Light libraries是一组通用的C基础库,目标是为减少重复造轮子而写实现了日志.原子操作.哈希字典.红黑树.动态库加载.线程.锁操作.配置文件.os适配层.事件驱动.工作队列.RPC.IPC ...

  7. 重复造轮子系列——基于Ocelot实现类似支付宝接口模式的网关

    重复造轮子系列——基于Ocelot实现类似支付宝接口模式的网关 引言 重复造轮子系列是自己平时的一些总结.有的轮子依赖社区提供的轮子为基础,这里把使用过程的一些觉得有意思的做个分享.有些思路或者方法在 ...

  8. 重复造轮子系列——基于FastReport设计打印模板实现桌面端WPF套打和商超POS高度自适应小票打印

    重复造轮子系列——基于FastReport设计打印模板实现桌面端WPF套打和商超POS高度自适应小票打印 一.引言 桌面端系统经常需要对接各种硬件设备,比如扫描器.读卡器.打印机等. 这里介绍下桌面端 ...

  9. Meteva——让预报检验不再重复造轮子

    更多精彩,请点击上方蓝字关注我们! 检验是什么?****预报准确率的客观表达 说到天气预报,你最先会想到什么? 早上听了预报,带了一天伞却没下一滴雨的调侃? 还是 "蓝天白云晴空万里突然暴风 ...

  10. 54 个官方 Spring Boot Starters 出炉!别再重复造轮子了…….

    在之前的文章,栈长介绍了 Spring Boot Starters,不清楚的可以点击链接进去看下. 前段时间 Spring Boot 2.4.0 也发布了,本文栈长再详细总结下最新的 Spring B ...

随机推荐

  1. adb uninstall

    adb shell pm list packages adb uninstall com.pa.pfac

  2. logstash 利用drop 丢弃过滤日志

    input { stdin { } } filter { grok { match => ["message","\s*%{TIMESTAMP_ISO8601}\s ...

  3. java实现——004替换空格

    1.创建新的字符串 public class T004 { public static void main(String[] args){ System.out.println(replaceBlan ...

  4. Java多线程优化方法及使用方式

    一.多线程介绍 在编程中,我们不可逃避的会遇到多线程的编程问题,因为在大多数的业务系统中需要并发处理,如果是在并发的场景中,多线程就非常重要了.另外,我们在面试的时候,面试官通常也会问到我们关于多线程 ...

  5. ES系列六、ES字段类型及ES内置analyzer分析

    一.背景知识 在Es中,字段的类型很关键: 在索引的时候,如果字段第一次出现,会自动识别某个类型,这种规则之前已经讲过了. 那么如果一个字段已经存在了,并且设置为某个类型.再来一条数据,字段的数据不与 ...

  6. zabbix 触发器

    概观 项目只收集数据.要自动评估传入数据,我们需要定义触发器.触发器包含一个表达式,该表达式定义数据的可接受级别的阈值. 如果这一级别超出了传入的数据,触发器将“ fire 触发”或进入“' Prob ...

  7. Docker save &amp; load

    docker save Estimated reading time: 1 minute Description Save one or more images to a tar archive (s ...

  8. windchill系统——一些功能查找

    1.创建产品 导航栏的浏览——>最近的产品——>全部查看——>新建产品——>填写“名称”.选择“模板”.一定的“说明”.“专用访问权限”一般选择“否”——>“确定”选项 ...

  9. [MySQL]表创建外键失败:ERROR 1005 (HY000): Can&#39;t create table (errno: 150)

    在数据库中建立一个新表(表引擎为InnoDB)时, 需要用到外键, 所以就在建表的时候加了一句foreign key (column) references table_name.但是执行时出现 ER ...

  10. js long类型的日期转成Date,字符串StringBuilder拼接

    longToDate.js //扩展Date的format方法 Date.prototype.format = function (format) { var o = { "M+" ...