使用翻译器和语言检测器 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,其中一些翻译语言选择可能在您的浏览器中不可用。