iT邦幫忙

2022 iThome 鐵人賽

DAY 15
0
Software Development

譯者會消失嗎?Maybe, but not today —— 你,才是更好的翻譯師系列 第 15

背景服務:一鍵翻譯漂亮直達 Google 翻譯 API

  • 分享至 

  • xImage
  •  

昨天我們在【彈出頁面】建立了一個輸入界面,
讓【背景服務】可以取得 API_KEY,
接下來 content.js 就可以發出請求,
透過 background.js 向外部取得翻譯的結果,
再把譯文送回到網頁的【原始內容】之中。

我們先在 content.js 裡,
設定【Alt+Shift+4】這組快速鍵,
(因為這裡按下了 Shift,
 所以其實是【Alt+Shift+$】這組快速鍵)

hotkeys = {
  ...
  'AltShift$': {
    desc: '一鍵翻譯(使用外部的 Google 翻譯 API)',
    handler: AltShift$,
  },
  ...
}

在這個快速鍵的處理函式中,
我們會先執行【Alt+1】所做的工作,
也就是先對網頁進行分句,再備份原文,
然後利用 sendMessage 的機制,
請【背景服務】向 Google 翻譯 API 取得譯文。

function AltShift$() {
  Alt1()
  // sent_html = document.body.innerHTML  // 全文送譯太浪費了
  // 把需要進行翻譯的各句連成一氣
  sent_html = ''
  document.querySelectorAll("sent").forEach((item)=>{
    sent_html += item.outerHTML
  })
  
  chrome.runtime.sendMessage({
    cmd: 'get_google_translation_V2', 
    data: {sent_html: sent_html}
  });
}

如果你夠細心的話,也許會注意到,
這裡的 sendMessage 只用了一個參數,
並沒有設定 callback 回調函式來接收回應。

這是因為向外部取回譯文,是一個很耗時的工作,
我們並不打算用 callback 回調函式接收回應,
而是讓【背景服務】稍後收到譯文時,
再次發出 sendMessage。

因此,我們稍後還會再用一個 onMessage,
來接收【背景服務】送回來的譯文,
並進行後續的動作。

另外,各位或許也有注意到,
這裡使用的是 chrome.runtime.sendMessage( ... ),
而不是昨天所使用的 chrome.tabs.sendMessage(...)。

這是因為外掛只有一個【彈出頁面】和一個【背景服務】,
並不需要特別指定。
但如果是反過來的情況,
(例如昨天從【彈出頁面】發出 message,
 要去 content.js 裡取得快速鍵說明)
由於瀏覽器裡可能有許多不同的頁面,
分別呈現在不同的 tab 頁籤中,
因此,只要是對著【原始內容】content.js 發出 message,
都必須使用 chrome.tabs.sendMessage(...),
然後在第一個參數中,指定所要發送的目標 tab id。

content.js 這邊的程式碼完成之後,
(其實目前只完成一半)
接著要來到 background.js,
用 onMessage 接受請求,
然後再向外部連線以取得翻譯結果。

...
chrome.runtime.onMessage.addListener( (message, sender, sendResponse) => {
  ...
  else if (message.cmd == 'get_google_translation_V2') {
    sent_html = message.data.sent_html

    if (api_key) {
      getGoogleTranslationV2(api_key, sent_html)
      .then((tran_sent_html)=> {
        // 取得譯文之後...
        ....
      })
    }
  }
  ...
}

我們把向外部取譯文的程式碼,寫成了一個函式:

async function getGoogleTranslationV2(api_key, text, tar_lang='zh-TW') {
  promise = fetch(`https://translation.googleapis.com/language/translate/v2?key=${api_key}`, 
    {method: 'post', body: JSON.stringify({ q: text, target: tar_lang })})
  .then(r=>r.json())
  .then(r=>r.data.translations[0].translatedText);

  return promise
}

這個函式裡採用了 fetch(),
透過 Google 翻譯 API 取得譯文。
函式送回來的是一個 Promise,
後面再繼續接 .then(..) 就可以進行後續處理。

實際上取回譯文之後,後續還要把譯文套入頁面,
並執行【Alt+3】所做的工作,也就是備份譯文資料。
這些工作都不是在 background.js 裡進行,
而是要回到 content.js 裡,
才能完成這後半段的工作。

因此,前面的程式碼在呼叫 getGoogleTranslationV2() 之後,
後面的 .then() 還要再次使用 sendMessage 的機制,
把譯文送回 content.js 進行後續的處理:

  ...
  getGoogleTranslationV2(api_key, sent_html)
  .then((tran_sent_html)=> {
    // 取得譯文之後...
    chrome.tabs.sendMessage(
      sender.tab.id, 
      {
        cmd: 'tran_sent_html', 
        data: {tran_sent_html: tran_sent_html}
      }
    );
  })
  ...

由於這裡要發送 message 回到 content.js,
所以採用的是 chrome.tabs.sendMessage(),
其中第一個參數,直接從外面的 sender 參數裡取得即可。
意思就是說,當初是誰過來請求譯文,現在就把譯文送回去給誰。

【背景服務】把譯文送了出來,
content.js 也必須透過 onMessage 來接收,
才能取得翻譯的結果。

chrome.runtime.onMessage.addListener( (message, sender, sendResponse) => {
  ...
  else if (message.cmd == 'tran_sent_html') {
    if (message.data.tran_sent_html) {
      // 譯文逐句套入
      var sent_nodes = new DOMParser().parseFromString(
        message.data.tran_sent_html, "text/html").body;
      var id2Tran_innerHTML = {}
      sent_nodes.querySelectorAll("sent").forEach((item,i)=>{
        id2Tran_innerHTML[i] = item.innerHTML
      })
      document.querySelectorAll("sent").forEach((item,i)=>{
        item.innerHTML = id2Tran_innerHTML[i]
      })
      translated = true
      // 備份譯文
      Alt3()
    }
  }
  ...
}

這裡可以看到,我們在取得翻譯結果之後,
會先把譯文套入頁面,然後再用 Alt3() 把譯文備份起來。
如此一來,原文與譯文就齊備了。
剩下的部分,就和前幾天所述大致相同了。

這一連串的動作,
全都會在按下【Alt+Shift+$】之後,
一鍵之內全部完成。

至此「一鍵翻譯」的功能,總算是大功告成。
接下來我們隨時可進入編輯模式,
進行後續的翻譯修改工作。

順帶一提,
我們的快速鍵用了鍵盤 4 上方這個代表錢的 $ 符號。
這應該算是個有趣的巧合。
因為這樣可以順便提醒使用者注意,
這種翻譯方式是有可能需要花錢的。
希望這樣能給各位起到一點提醒的作用。

無論如何,
我們今天總算完成一鍵翻譯的快捷功能了。
使用起來真的是乾淨俐落,暢爽無比呀!! ^^
想讓人花錢的東西,果然一定要好用才行 ^
^

明天終於要放假了!
這段時間大家也辛苦了!
有機會一定要好好休息一下喲! ^_^


上一篇
背景服務:想出去玩沒問題,但要先拿到鑰匙呀!
下一篇
保存設定的各種姿勢——chrome.storage 與 options 選項頁面
系列文
譯者會消失嗎?Maybe, but not today —— 你,才是更好的翻譯師30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言