今天星期五,又一個愉快的週末快到了,當我腳步輕快地回到家,準備擁抱女朋友的時候,卻發現,女朋友愁眉苦臉,望著電腦上一堆英文資料夾,不斷的唉聲嘆氣並嘟喃道:“好累啊”。於是,我湊近一看,只見她電腦上一堆英文資料夾,不斷的重複著複製檔名,然後放百度翻譯裡翻譯成中文,然後又把翻譯後的結果給檔案重新命名,這也太難受了吧。想到女朋友有難,我作為她的程式猿男朋友,怎麼能袖手旁觀,我陷入了沉思,突然想到用Node不就能做到她手上的那些操作嗎,於是說做就做,我立馬把女朋友拋在身後,開啟電腦開始行動,畢竟女人只會影響我拔劍的速度。
專案搭建
專案搭建依舊使用的是老組合,
Electron + Vue + Node
,這次就不講怎麼整合electron和vue了,具體可看 Electron+vue從零開始打造一個本地音樂播放器這篇文章。懶人可透過克隆我的模板檔案直接開發。
專案功能
明確要解決的幾個痛點:
要能自動翻譯
要能將翻譯好的名字自動重新命名
要能批次翻譯
希望能操作簡單,能拖拽一個目錄,或拖拽檔案
需求明確了,下面咱們一步一步來逐個解決。實現效果
專案實現
專案實現並不複雜,逐一解決,有的放矢。
自動翻譯
測試過有道翻譯,百度翻譯,谷歌翻譯。經過對比,最終選擇了百度翻譯,百度翻譯的通用翻譯每月200萬字符的免費,(QPS=10)還是很符合我的需求的。
註冊申請翻譯服務
要使用翻譯服務需要去百度翻譯開放平臺申請使用許可權,選擇通用翻譯服務就可以了,註冊成為開發者後,新建專案獲取appid,這個appid很重要,決定了是否能正確發起翻譯請求。
拼接翻譯API
透過檢視文件可知,通用翻譯API HTTP地址為
https://api。fanyi。baidu。com/api/trans/vip/translate
可攜帶下面這些引數
由於安全限制,需要生成簽名,簽名需要 按照 appid+q+salt+金鑰 的順序拼接得到字串,然後對字串進行md5加密
const salt = parseInt(Math。random() * 1000000000); const sign = md5(globalData。appid + q + salt + globalData。key);複製程式碼
生成簽名後拼接請求的URL
const params = encodeURI( `q=${q}&from=auto&to=${globalData。to}&appid=${globalData。appid}&salt=${salt}&sign=${sign}` );
翻譯功能程式碼
const md5 = require(“md5”);var rp = require(“request-promise”);const { globalData } = require(“。/config。js”);function translate(msg) { const q = msg; const salt = parseInt(Math。random() * 1000000000); //加鹽 const sign = md5(globalData。appid + q + salt + globalData。key); //生成簽名 const params = encodeURI( `q=${q}&from=auto&to=${globalData。to}&appid=${globalData。appid}&salt=${salt}&sign=${sign}` ); const options = { uri: `https://fanyi-api。baidu。com/api/trans/vip/translate?${params}`, }; return rp(options)。then((res) => JSON。parse(res)。trans_result);}module。exports = { translate,};
主體功能實現
主體功能分為:
批次翻譯,支援向下遞迴翻譯
拖拽不定量檔案,或者拖拽資料夾翻譯
重新命名
批次翻譯
要實現批次需要獲取到目標資料夾路徑,然後透過
fs.readdir
讀取到目錄下檔案資訊,遍歷檔案資訊,如果是檔案,對檔名和字尾進行分割,然後再進行翻譯操作,如果是目錄,就執行遞迴操作。
// 讀取目錄中的所有檔案/目錄 fs。readdir(dirPath, (err, files) => { if (err) { // throw err; dialog。showMessageBox({ type: ‘info’, title: ‘確認’, message: ‘請確認是否選擇了目錄’, }); this。loading = false; throw err; } files。forEach((fileItem) => { //遍歷檔案 fs。stat(fullPath, (err, stat) => { if (err) { throw err; } // 判斷是否為檔案 if (stat。isFile()) { //處理檔名 } else if (stat。isDirectory()) { // 遞迴翻譯 this。startTrans(fullPath); } }); }); });
獲取資料夾路徑
獲取資料夾路徑有兩種方式獲取:
設定input webkitdirectory directory屬性,然後監聽change事件獲取到所選擇資料夾的路徑
getFile(e) { this。path = e。target。files[0]。path;},
透過H5的拖拽API監聽drop事件,獲取到 DataTransfer 物件,DataTransfer 物件用於儲存拖動並且放下的資料。
分割檔名和字尾
由於是翻譯檔名,所以需要透過
path.extname
將檔名與字尾分割開來,翻譯後再將檔名重新組織,需要注意的是這裡需要處理下檔名中的特殊字元,特殊字元會影響翻譯結果,可能會導致翻譯失敗。
// 獲取檔案的字尾格式const suffixName = path。extname(fileItem); // 獲取字首const initSubFileName = this。removeSymbol( fileItem。split(suffixName)[0]);// 移除檔名中的特殊字元removeSymbol(fileName) { const reg = /[`~_!@#$^&*%()=|{}‘:;’,。<>\\/?~!@#¥……&*()——|{}‘;:“”’。,、?\s]/g; const newFile = fileName。replace(reg, “ ”); return newFile;},
翻譯檔名
對分割好的檔名進行翻譯,然後重新新的檔名稱,這裡要注意的是,由於百度翻譯限制了(QPS=10),所以需要新增對翻譯請求節流,限制其每秒不能超過10次。
節流函式
const { globalData } = require(“。/config。js”);const throttle = (function(delay = 1500) { const wait = []; let canCall = true; return function throttle(callback) { if (!canCall) { if (callback) wait。push(callback); return; } callback(); canCall = false; setTimeout(() => { canCall = true; if (wait。length) { throttle(wait。shift()); } }, delay); };})(globalData。delay);module。exports = { throttle};
翻譯後重組檔名
throttle(() => { translate(initSubFileName)。then(res => { if (res) { // 如果有【】保留檔名,如果沒有就加上【】 const target = this。checkName(res[0]。dst); // 拼接帶字尾的檔名 const fullSuffixName = `${target}${suffixName}`; // 翻譯後的檔案路徑 const newPath = path。resolve(dirPath, fullSuffixName); } else { // 翻譯失敗 console。log(“翻譯介面服務出錯”); dialog。showMessageBox({ type: “error”, title: “錯誤”, message: “翻譯介面服務出錯” }); } }); });
重新命名
重新命名使用node自帶的 fs。rename
fs。rename(oldPath, newPath, err => { if (err) { dialog。showErrorBox(“錯誤”, “翻譯失敗,請關閉軟體重試”); this。loading = false; throw err; } console。log(`${initSubFileName} 已翻譯成 ${fullSuffixName}`); this。path = `${initSubFileName} 已翻譯成 ${fullSuffixName}`; });
最後
終於完成了,我伸了伸懶腰,我興高采烈地準備去女朋友那邀功,不小心摔了一跤,我猛地起來,啊,還好,原來是一場夢!不對!按這麼說,我的女朋友。。。。我突然傷感起來,悲傷地打開了網易雲:
生不出人,我很抱歉!
原來這一切都是假的!!!那晚,淚浸溼了我的枕頭!!!