用Java做一個及時翻譯工具
平時看英文文件或者查詢資料的時候,遇到了不懂的單詞,就要去百度,然後就會很麻煩。於是就想到用Java寫一個及時翻譯的小工具!
預期的實現效果: 雙擊選中一個單詞,按下Ctrl+C進行復制 然後馬上顯示出對應單詞的中文翻譯
首先基本思路是這樣的:
- 首先獲取系統剪下板的內容
- 將該內容傳送到網頁上,然後獲取網頁的原始碼,查詢到對應的中文解釋
- 將中文翻譯顯示出來
以上就是基本的思路!但是實際操作的時候還是遇到了很大的困難的。
先寫兩個介面
得到剪下板的內容
這個並不是很困難,畢竟java有提供對應的API,程式碼如下:
package translate;import java.awt.Toolkit;import java.awt.datatransfer.Clipboard;import java.awt.datatransfer.DataFlavor;import java.awt.datatransfer.Transferable;public class ClipboradUtils { protected static String getClipboardText() throws Exception{ Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();//獲取系統剪貼簿 // 獲取剪下板中的內容 Transferable clipT = clip.getContents(null); if (clipT != null) { // 檢查內容是否是文字型別 if (clipT.isDataFlavorSupported(DataFlavor.stringFlavor)) return (String)clipT.getTransferData(DataFlavor.stringFlavor); } return null; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
以上是放在一個工具類,做成靜態函式方便呼叫!
獲取網頁原始碼
首先想到是就是去百度翻譯
我們在這裡翻譯單詞 blue 我們看位址列http://fanyi.baidu.com/?aldtype=16047#en/zh/blue
,剛好我們要翻譯的單詞就在最後,所以只要爬取頁面http://fanyi.baidu.com/?aldtype=16047#en/zh/待查單詞
的原始碼,然後做一些篩選就可以了! 然後事情進展的卻並不是那麼的順利,百度的這個應該是為了防止爬取,所以翻譯的操作應該是Dom操作,原始碼上面毫無翻譯痕跡。 這個方法就終止了。
然後想到的是百度翻譯是否有開放介面 果然,百度翻譯提供了開放的介面,但是貌似要收費。 http://api.fanyi.baidu.com/api/trans/product/index 當然,我建議大家用這個方法,畢竟人家公司也不容易,而且功能也相對很豐富。
但是,如果真的不想花錢就不行了嗎?答案是否定的!
意外收穫 我在百度直接搜尋一個單詞的是否發現也會出現對應的翻譯!如下:
然後檢視一下原始碼,搜尋藍色
,果然,原始碼上面是有翻譯結果的(偷笑)。
而且對應的翻譯內容就在<span class="op_dict_text2">
和</span>
之間! 百度搜索的url對應的是http://www.baidu.com/s?wd="搜尋內容"
於是就可以把獲取翻譯內容的工具類寫好了,程式碼如下:
package translate;import java.io.BufferedReader;import java.io.InputStreamReader;import java.net.HttpURLConnection;import java.net.URL;public class GetHtmlContentUtils { private final static String PreUrl="http://www.baidu.com/s?wd="; //百度搜索URL private final static String TransResultStartFlag="<span class=\"op_dict_text2\">"; //翻譯開始標籤 private final static String TransResultEndFlag="</span>"; //翻譯結束標籤 public static String getTranslateResult(String urlString) throws Exception { //傳入要搜尋的單詞 URL url = new URL(PreUrl+urlString); //生成完整的URL // 開啟URL HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); // 得到輸入流,即獲得了網頁的內容 BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); String preLine=""; String line; int flag=1; // 讀取輸入流的資料,並顯示 String content=""; //翻譯結果 while ((line = reader.readLine()) != null) { //獲取翻譯結果的演算法 if(preLine.indexOf(TransResultStartFlag)!=-1&&line.indexOf(TransResultEndFlag)==-1){ content+=line.replaceAll(" | ", "")+"\n"; //去電原始碼上面的半形以及全形字元 flag=0; } if(line.indexOf(TransResultEndFlag)!=-1){ flag=1; } if(flag==1){ preLine=line; } } return content;//返回翻譯結果 }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
再寫一個窗體介面
注:有了上面的核心演算法,下面的其實都隨意實現了!
介面實現
我設計的窗體介面如下:
簡單說一下介面佈局:最上面一個JTextField
和JCheckBox
,下面是JTextArea
。
簡單說一下各個控制元件的作用: JTextField:顯示待翻譯的單詞 JCheckBox:表示是從剪下板獲取單詞還是自己直接輸入 JTextArea:顯示翻譯結果
實現思路
介面已經實現完成了,那麼思路是什麼呢? 我的思路是這樣的:
- 開啟一個執行緒,將JTextField裡面的值不斷設定為剪下板裡面的值
- 如果JTextField裡面的值改變了(剪下板的值改變了,也就是選中複製了新的單詞),呼叫GetHtmlContentUtils 裡面的方法獲取翻譯的結果,並顯示!
對應程式碼如下:
package translate;import java.awt.BorderLayout;import java.awt.Container;import java.awt.FlowLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.JCheckBox;import javax.swing.JFrame;import javax.swing.JTextArea;import javax.swing.JTextField;import javax.swing.border.LineBorder;import javax.swing.event.DocumentEvent;import javax.swing.event.DocumentListener;public class MainFrame extends JFrame implements Runnable { private JTextField srcContentTextField; // 記錄剪下板的內容 private JTextArea resContentTextField; // 記錄翻譯的內容 private JCheckBox translateFlag; //標記單詞的獲取來源 //選中:手動輸入 未選中:剪下板獲取 private Container topContainer; public MainFrame() {//初始化控制元件 srcContentTextField = new JTextField(10); resContentTextField = new JTextArea(); translateFlag = new JCheckBox(); topContainer = new Container(); } public void setMinWindowLayout() { // TODO Auto-generated method stub //佈局設定 resContentTextField.setBorder(new LineBorder(new java.awt.Color(127, 157, 185), 1, false)); this.setLayout(new BorderLayout()); this.add(this.resContentTextField); translateFlag.setToolTipText("手動輸入取詞"); topContainer.setLayout(new BorderLayout()); topContainer.add(srcContentTextField, BorderLayout.CENTER); topContainer.add(translateFlag, BorderLayout.EAST); this.add(this.topContainer, BorderLayout.NORTH); this.setResizable(false); translateFlag.addActionListener(new ActionListener() {//設定JCheckBox的監聽 @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub if (translateFlag.isSelected()) { translateFlag.setToolTipText("自動複製取詞"); //設定提示 } else { translateFlag.setToolTipText("手動輸入取詞"); } } }); //監聽JTextField裡面內容改變的事件 srcContentTextField.getDocument().addDocumentListener(new DocumentListener() { @Override public void changedUpdate(DocumentEvent arg0) { } @Override public void insertUpdate(DocumentEvent arg0) { //內容改變 try { //呼叫介面獲取翻譯結果 String result = GetHtmlContentUtils.getTranslateResult(srcContentTextField.getText()); if (result == "") result = "!Sorry,未找到該詞!"; resContentTextField.setText(result);//顯示翻譯結果 } catch (Exception e) { // TODO Auto-generated catch block resContentTextField.setText("!Sorry,未找到該詞!"); } } @Override public void removeUpdate(DocumentEvent arg0) { } }); this.validate(); } @Override public void run() { // TODO Auto-generated method stub while (true) { if (!translateFlag.isSelected()) { //如果JCheckBox沒有被選中,則從剪下板獲取單詞 try { String content = ClipboradUtils.getClipboardText(); srcContentTextField.setText(getSimpleWord(content)); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static String getSimpleWord(String content) {//去掉切板裡面的一些特殊字元 return content.replace(".", "").replace(",", "") .replace("'", "").replace(":", "") .replace(";", "").trim(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
接下來就是main函數了,程式碼如下:
package translate;import javax.swing.JFrame;public class TranslateTool { public static void main(String[] args) { MainFrame mainFrame = new MainFrame(); mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainFrame.setBounds(300, 200, 400, 300); mainFrame.setVisible(true); mainFrame.setAlwaysOnTop(true);//設定在最頂層 mainFrame.setMinWindowLayout(); Thread t = new Thread(mainFrame); t.start(); //開啟執行緒 }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
程式執行結果
隨手翻譯了下 public 關鍵字,感覺還是可以的!
以下是2017/03/19日的補充 從eclipse匯出jar包時候,發現顯示的翻譯亂碼了。 找了半天的資料,有以下兩種解決方案:
- 在控制檯執行:
java -Dfile.encoding=utf-8 -jar C:\Users\lenovo\Desktop\TranslateTool.jar(可執行jar的路徑)
現在就可以在系統環境變數中增加一個變數,變數名為: JAVA_TOOL_OPTIONS, 變數值為:-Dfile.encoding=UTF-8
這樣就基本可以解決亂碼問題。如果你有好的解決方案,歡迎留言