超强网页翻译(可用于翻译API文档)

相信有不少人很讨厌,谷歌翻译把代码或其他一些不该翻译的东西翻译了,观看感受奇差,于是我就有了做一款部分选择翻译的工具的想法

首先我想到的是使用css选择器,选择那部分不翻译,不过实现太麻烦,改为那部分选择并翻译。
整个项目使用Java开发,不太方便在浏览器使用,可以考虑写个js版,作为浏览器插件使用,每个页面运行时执行一下,当然也可以在js中执行其他逻辑如移除广告等。
Javs使用的Jsoup对文档进行解析

第一版

先使用CSS选择器,在使用正则表达式把内部文本翻译,可以复用StringBuffer,只需要一遍就完成了,效率比较高。

public class HtmlTranslator {
    private String source;
    private String[] select;
    private StringBuffer buffer;
    private Pattern pattern;
    private BaiduTranslator baiduTranslator;
    public HtmlTranslator(String source) {
        this.source=source;
        initData();
    }
    public HtmlTranslator() {
        this(null);
    }
    private void initData() {
        buffer=new StringBuffer();
        pattern = Pattern.compile(">(.*?)<",Pattern.DOTALL);
        baiduTranslator=new BaiduTranslator("en","zh");
    }
    public void setSelect(String ...select) {
        this.select=select;
    }
    @SneakyThrows
    public void translation(String path){
        source=path;
        Files.write(Paths.get(path),translation().getBytes());
    }
    @SneakyThrows
    public String translation() {
        if(source==null)throw new RuntimeException("必须指定目标文件");
        Document document = Jsoup.parse(new File(source),"UTF-8");
        handleDocument(document);
        return document.html();
    }
    private void handleDocument(Document document) {
        if(select==null)return;
        for (int i = 0; i < select.length; i++) {
            handleSelect(document,select[i]);
        }
    }
    // 处理一个选择器
    private void handleSelect(Document document, String select) {
        Elements elements = document.select(select);
        elements.forEach(element -> {//toString  获取标签的全部内容
            buffer.setLength(0);
//            System.out.println(element.toString());
            Matcher matcher = pattern.matcher(element.toString());
            while (matcher.find()){
                String translation=Translation(matcher.group(1));
                matcher.appendReplacement(buffer,">"+translation+"<");
            }
            matcher.appendTail(buffer);
            trimBuffer();
            element.html(buffer.toString());//直接插入 文本当html不转义
        });
    }
    // 翻译
    @SneakyThrows
    private String Translation(String str) {
//        System.out.println(str);
        if(str.trim().isEmpty())return "";
//        return baiduTranslator.translationHtml(str);
        return "翻译后的文本";
    }
    //  移除  两边的标签
    private void trimBuffer() {
        buffer.setLength(buffer.lastIndexOf("<"));
        buffer.delete(0,buffer.indexOf(">")+1);
    }

}

不过缺点也比较明显,没有对选中标签内的嵌套标签进行再次筛选,选择元素必须足够小

第二版

使用递归,对选择的标签当作文档再次选择,精确选择

public class HtmlTranslator {
    private String[] select;
    private BaiduTranslator baiduTranslator;
    public HtmlTranslator() {
        baiduTranslator=new BaiduTranslator("en","zh");
    }
    public void setSelect(String ...select) {
        this.select=select;
    }
    @SneakyThrows
    public void translationHtml(String path){
        Document document = Jsoup.parse(new File(path),"UTF-8");
        handleElement(document);
//        System.out.println(document);//TODO
        Files.write(Paths.get(path),document.html().getBytes());
    }
    private void handleElement(Element element) {
        if(select==null)return;
        for (int i = 0; i < select.length; i++) {
            handleSelect(element,select[i]);
        }
    }
    // 处理一个选择器
    private void handleSelect(Element parentElement, String select) {
        Elements elements = parentElement.select(select);
        elements.forEach(sonElement -> {
            StringBuilder buffer = new StringBuilder();
            List<Node> nodes = sonElement.childNodes();
            for (Node node:nodes){
                if(node instanceof TextNode){
                    TextNode textNode= (TextNode) node;
                    String text = textNode.text();
                    String translation = translation(text);
                    buffer.append(translation);
                }else if(node instanceof Element){
                    Element element= (Element) node;
                    handleElement(element);
                    buffer.append(element);
                }
            }
            sonElement.html(buffer.toString());//直接插入 文本当html不转义
        });
    }
    // 翻译
    @SneakyThrows
    private String translation(String str) {
//        System.out.println(str);
        if(str.trim().isEmpty())return "";
//        return baiduTranslator.translationHtml(str);
        return "翻译后的文本";
    }
}

虽然因为递归StringBuilder不能复用,而且递归降低了一点效率(实测并没有降低多少),但是选择变得非常精确。

使用翻译文档的方式进行测试

这里文档选择GameMaker Studio 2英文帮助文档,因为百度翻译有访问频率限制,暂时,将翻译后的文本使用 翻译后的文本 表示
在这里插入图片描述
共翻译2427个页面用时11s
原页面
在这里插入图片描述
翻译后
在这里插入图片描述
可见就算要保护的文本与要翻译的文本层层嵌套,还是可以正确识别并翻译css选择的文本
再看看最重要的代码
在这里插入图片描述
代码被完美的保留了下来,连参数说明中的代码引用也被保留的下来

最后

希望谷歌翻译早日开发出鼠标选中元素保护不翻译的功能,谷歌浏览器本来就支持右键选中元素css,它要做应该不会太难

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值