使用翻譯器和語言檢測器 API

翻譯器和語言檢測器 API 提供非同步(基於 Promise)機制,供網站透過瀏覽器自身的內部 AI 模型檢測語言和翻譯文字。這非常有用且高效,因為瀏覽器負責處理服務,而開發者無需依賴使用者下載 AI 模型,或自行託管/付費給基於雲的翻譯服務。本文將介紹如何使用這些 API。

檢測語言

所有語言檢測功能都透過 LanguageDetector 介面訪問。

讓 AI 模型檢測語言的第一步是建立一個 LanguageDetector 物件例項。這透過呼叫 LanguageDetector.create() 靜態方法來完成,該方法接受一個選項物件作為引數。

js
const detector = await LanguageDetector.create({
  expectedInputLanguages: ["en-US", "zh"],
});

expectedInputLanguages 屬性指定了你期望輸入到檢測器的語言,以幫助提高語言檢測的準確性。

注意: 不同的實現可能支援不同的語言。

建立 LanguageDetector 例項後,可以透過在該例項上呼叫 LanguageDetector.detect() 例項方法來使用它進行語言檢測,並將要檢查的文字作為引數傳遞。

js
const results = await detector.detect(myTextString);

此方法返回一個表示檢測到的潛在語言匹配項的物件陣列。每個物件包含:

  • 一個字串,包含表示檢測到的語言的 BCP 47 語言標籤
  • 一個介於 0 和 1 之間的數字,表示該匹配項的置信度得分。

所以例如:

js
results.forEach((result) => {
  console.log(`${result.detectedLanguage}: ${result.confidence}`);
});

// Results in logs like this:
// la: 0.8359838724136353
// es: 0.017705978825688362
// sv: 0.012977192178368568
// en: 0.011148443445563316
// und: 0.0003214875760022551

注意: 陣列的最後一個元素始終表示 und (undetermined,未確定) 語言的置信度得分,表示文字不是模型所知語言的可能性。

建立翻譯

翻譯遵循與語言檢測非常相似的模式。透過呼叫 Translator.create() 靜態方法建立一個 Translator 物件例項,該方法接受一個選項物件,其中必須至少包含 sourceLanguagetargetLanguage

js
const translator = await Translator.create({
  sourceLanguage: "en",
  targetLanguage: "ja",
});

然後透過呼叫 Translator.translate() 例項方法來建立翻譯,並將要翻譯的文字字串作為引數傳遞。

js
const translation = await translator.translate(myTextString);

此方法返回一個包含翻譯的字串。

還有一個 translate() 方法的流式版本——Translator.translateStreaming()——允許你將翻譯作為 ReadableStream 返回。這在翻譯大量文字時非常有用。

js
const stream = translator.translateStreaming(myTextString);
let translation = "";

for await (const chunk of stream) {
  translation += chunk;
}

console.log("Stream complete");
console.log(translation);

檢查配置支援

在建立 LanguageDetectorTranslator 物件之前,可以使用 LanguageDetector.availability()Translator.availability() 靜態方法來檢查當前瀏覽器是否支援你想要的語言配置。例如:

js
const detectorAvailability = await LanguageDetector.availability({
  expectedInputLanguages: ["en-US", "ja"],
});

const translatorAvailability = await Translator.availability({
  sourceLanguage: "en",
  targetLanguage: "ja",
});

這些方法返回一個列舉值,指示是否支援或將支援指定的選項集。

  • downloadable 表示實現支援所請求的選項,但需要下載模型或一些微調資料。
  • downloading 表示實現支援所請求的選項,但需要完成正在進行的下載。
  • available 表示實現支援所請求的選項,無需任何新下載。
  • unavailable 表示實現不支援所請求的選項。

如果需要下載,一旦使用相關的 create() 方法建立了 LanguageDetectorTranslator 例項,瀏覽器將自動開始下載。你可以使用 監控器 自動跟蹤下載進度。

取消操作和銷燬例項

你可以使用 AbortController 來取消掛起的檢測或翻譯操作,並將相關的 AbortSignal 作為 signal 屬性值包含在方法選項物件中。例如,中止 Translator.create() 操作將如下所示:

js
const controller = new AbortController();

const translator = await Translator.create({
  sourceLanguage: detectedLanguage,
  targetLanguage: formData.get("translateLanguage"),
  signal: controller.signal,
});

// ...

controller.abort();

一旦建立了 TranslatorLanguageDetector 例項,當不再需要時,就可以使用 Translator.destroy()/LanguageDetector.destroy() 方法將其銷燬。

js
translator.destroy();
detector.destroy();

如果這些物件不再使用,銷燬它們是明智的,因為它們在處理過程中會佔用大量資源。

監控下載進度

如果特定檢測或翻譯的 AI 模型正在下載(availability() 返回 downloadabledownloading),提供使用者反饋告訴他們還需要等待多久才能完成操作會很有幫助。

TranslatorLanguageDetectorcreate() 方法可以接受一個 monitor 屬性,其值是一個回撥函式,該函式接受一個 CreateMonitor 例項作為引數。CreateMonitor 有一個可用的 downloadprogress 事件,當 AI 模型下載取得進展時會觸發該事件。

你可以使用此事件來顯示載入進度資料:

js
translator = await Translator.create({
  sourceLanguage: "en",
  targetLanguage: "ja",
  monitor(monitor) {
    monitor.addEventListener("downloadprogress", (e) => {
      console.log(`Downloaded ${Math.floor(e.loaded * 100)}%`);
    });
  },
});

如果指定的語言不受支援,將不會啟動下載,並且會丟擲 NotSupportedError DOMException

使用配額

某些實現有一個輸入配額,用於規定一個網站在給定時間段內可以請求的操作次數。總配額可以透過 Translator.inputQuota/LanguageDetector.inputQuota 屬性訪問,而特定翻譯或語言檢測的配額使用情況可以使用 Translator.measureInputUsage()/LanguageDetector.measureInputUsage() 方法返回。

例如,下面的程式碼片段透過 Translator.inputQuota 返回總輸入配額,並透過 Translator.measureInputUsage() 返回翻譯特定文字字串的輸入配額使用情況。

然後,我們測試該字串的單個輸入使用量是否大於總可用配額。如果是,則丟擲相應的錯誤;如果不是,則使用 translate() 開始翻譯字串。

js
const translator = await Translator.create({
  sourceLanguage: "en",
  targetLanguage: "ja",
});

const totalInputQuota = translator.inputQuota;
const inputUsage = await translator.measureInputUsage(myTextString);

if (inputUsage > totalInputQuota) {
  throw new Error("Insufficient quota to translate.");
} else {
  console.log("Quota available to translate.");
  const translation = await translator.translate(myTextString);
  // ...
}

如果您嘗試執行超出可用配額的語言檢測或翻譯操作,將丟擲 QuotaExceededError DOMException

完整示例

讓我們來看一個完整的示例,演示翻譯器和語言檢測器 API 的實際應用。

HTML

在我們的標記中,我們首先定義一個輸入 <form>,允許使用者設定要翻譯的文字以及要翻譯成的語言。這包括一個用於輸入文字本身的 <textarea>,一個用於顯示檢測到的語言的 <output> 元素,以及一個用於選擇翻譯語言的 <select> 元素。

html
<h2>Input</h2>

<form>
  <div>
    <label for="translate-text">Enter text to translate:</label>
    <textarea id="translate-text" name="translateText" rows="6"></textarea>
    <output class="detected-language">Detected language: </output>
  </div>
  <div>
    <label for="translate-language">Choose translation language:</label>
    <select id="translate-language" name="translateLanguage">
      <option value="en" selected>English (en)</option>
      <option value="fr">French (fr)</option>
      <option value="de">German (de)</option>
      <option value="it">Italian (it)</option>
      <option value="zh">Mandarin Chinese (zh)</option>
      <option value="zh-Hant">Taiwanese Mandarin (zh-Hant)</option>
      <option value="ja">Japanese (ja)</option>
      <option value="pt">Portuguese (pt)</option>
      <option value="ru">Russian (ru)</option>
      <option value="es">Spanish (es)</option>
      <option value="tr">Turkish (tr)</option>
      <option value="hi">Hindi (hi)</option>
      <option value="vi">Vietnamese (vi)</option>
      <option value="bn">Bengali (bn)</option>
    </select>
  </div>
  <button type="submit">Translate</button>
</form>

我們標記的後半部分包含一個 <p> 元素,用於顯示生成的翻譯。

html
<h2>Translation output</h2>

<p class="translate-output"></p>

請注意,我們不會在此示例中顯示 CSS,因為它與理解翻譯器和語言檢測器 API 無關。

JavaScript

在我們的指令碼中,我們首先獲取對 <form><textarea>、提交 <button>、翻譯輸出 <p> 和語言檢測 <output> 元素的引用。我們還宣告一個名為 detectedLanguage 的變數來儲存語言檢測操作的結果。

js
const form = document.querySelector("form");
const textarea = document.querySelector("textarea");
const submitBtn = document.querySelector("button");

const translateOutput = document.querySelector(".translate-output");
const detectedLanguageOutput = document.querySelector(".detected-language");
let detectedLanguage = "";

接下來,我們使用 EventTarget.addEventListener() 方法監聽兩個事件:

  • <form> 元素上的 submit 事件;當表單提交時,將呼叫 handleTranslation() 函式。
  • <textarea> 元素上的 input 事件;當 <textarea> 的當前值發生變化時,將呼叫 detectLanguage() 函式。
js
form.addEventListener("submit", handleTranslation);
textarea.addEventListener("input", detectLanguage);

接下來定義的 detectLanguage() 函式首先檢查 <textarea> 元素的長度是否大於 20 個字元。如果是,則繼續進行語言檢測。如果不是,則停用提交按鈕,並在 <output> 元素的 textContent 中顯示一條訊息,說明文字太短,無法檢測語言。我們這樣做是因為語言檢測通常對單個單詞和非常短的短語效果不佳。如果您經常處理短文字,請仔細測試您的優先語言,並在置信度太低時將結果返回為未知。

當檢測輸入文字的語言時,我們使用 create() 方法建立一個 LanguageDetector 例項,其中包括一個 monitor,用於在模型下載時間較長時記錄下載進度。然後,我們使用 detect() 方法檢測語言,並將 <textarea> 的值傳遞給它。當返回結果時,我們將最高結果的語言和置信度寫入 <output> 元素。在更復雜的應用程式中,您可能希望報告多個結果,甚至讓使用者選擇語言,但這足以用於演示。

最後,我們將提交按鈕設定為不停用,以便表單可以提交以開始翻譯。

js
async function detectLanguage() {
  if (textarea.value.length > 20) {
    const detector = await LanguageDetector.create({
      monitor(monitor) {
        monitor.addEventListener("downloadprogress", (e) => {
          console.log(`Downloaded ${e.loaded * 100}%`);
        });
      },
    });

    const results = await detector.detect(textarea.value);
    detectedLanguageOutput.textContent = `Detected language: ${
      results[0].detectedLanguage
    }. Confidence: ${results[0].confidence.toFixed(4)}`;
    detectedLanguage = results[0].detectedLanguage;

    submitBtn.disabled = false;
  } else {
    detectedLanguageOutput.textContent = `Text too short to accurately detect language.`;
    detectedLanguage = "";

    submitBtn.disabled = true;
  }
}

現在我們定義 handleTranslation() 函式。在防止表單預設提交後,我們建立一個新的 FormData 物件例項,其中包含我們的 <form> 資料名稱/值對。然後,我們執行資料驗證測試,檢查檢測到的 <textarea> 內容語言是否與選擇的翻譯語言 (translateLanguage) 相同。如果是,我們在類為 translate-output<p> 中列印一條錯誤訊息。

js
async function handleTranslation(e) {
  e.preventDefault();

  const formData = new FormData(form);

  if (formData.get("translateLanguage") === detectedLanguage) {
    translateOutput.innerHTML = `<span class="error">Input language and translation language are the same.</span>`;
    return;
  }
  translateOutput.innerHTML = "";

如果測試透過,我們將開啟一個 try { ... } 塊。我們首先使用 availability() 方法檢查介於檢測到的輸入和選擇的輸出語言之間的翻譯模型的可用性。

  • 如果它返回 unavailable,我們在類為 translate-output<p> 中列印一條適當的錯誤訊息。
  • 如果它返回 available,我們使用 create() 方法建立一個翻譯器,並將檢測到的輸入和選擇的輸出語言傳遞給它。所需的 AI 模型可用,因此我們可以立即使用它。
  • 如果它返回不同的值(即 downloadabledownloading),我們執行相同的 create() 方法呼叫,但這次我們包含一個 monitor,每次 downloadprogress 事件觸發時,該 monitor 會將模型下載的百分比列印到 translate-output <p>
js
  try {
    const availability = await Translator.availability({
      sourceLanguage: detectedLanguage,
      targetLanguage: formData.get("translateLanguage"),
    });
    let translator;

    if (availability === "unavailable") {
      translateOutput.innerHTML = `<span class="error">Translation not available; try a different language combination.</span>`;
      return;
    } else if (availability === "available") {
      translator = await Translator.create({
        sourceLanguage: detectedLanguage,
        targetLanguage: formData.get("translateLanguage"),
      });
    } else {
      translator = await Translator.create({
        sourceLanguage: detectedLanguage,
        targetLanguage: formData.get("translateLanguage"),
        monitor(monitor) {
          monitor.addEventListener("downloadprogress", (e) => {
            translateOutput.textContent = `Downloaded ${Math.floor(
              e.loaded * 100
            )}%`;
          });
        },
      });
    }

接下來,我們將輸出 <p> 的內容設定為待處理訊息,並停用提交按鈕,然後在呼叫 Translator.translate() 執行實際翻譯,並將 <textarea> 的值傳遞給它。翻譯完成後,我們將其顯示在輸出 <p> 中,然後再啟用提交按鈕。

js
translateOutput.textContent = "...generating translation...";
submitBtn.disabled = true;

const translation = await translator.translate(formData.get("translateText"));

translateOutput.textContent = translation;
submitBtn.disabled = false;

最後,我們包含 try 塊的對應 catch() { ... } 塊。如果 try 內容引發了任何型別的異常,我們將其顯示在輸出 <p> 中。

js
  } catch (e) {
    translateOutput.innerHTML = `<span class="error">${e}</span>`;
  }
}

結果

渲染後的示例如下所示:

嘗試在 <textarea> 中輸入一段文字,並注意僅當字元數大於 20 時才報告檢測到的語言和置信度。選擇一種與輸入文字不同的翻譯語言,然後按提交按鈕生成 AI 生成的翻譯。

即使您的瀏覽器支援這些 API,其中一些翻譯語言選擇可能在您的瀏覽器中不可用。