谷歌浏览器将提供内置翻译和语言检测 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}`);
});

// 日志输出如下:
// la: 0.8359838724136353
// es: 0.017705978825688362
// sv: 0.012977192178368568
// en: 0.011148443445563316
// und: 0.0003214875760022551

注意: 数组的最后一个元素始终表示 und 语言的置信度分数——这是“未确定”的缩写,表示文本不是用模型已知语言书写的概率。

创建翻译

翻译与语言检测遵循非常相似的模式。通过调用 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()] (https://developer.mozilla.org/en-US/docs/Web/API/LanguageDetector/availability_static “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 异常。

完整示例

让我们来看一个完整示例,演示 Translator 和 Language Detector 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>
* {
  box-sizing: border-box;
}

html {
  font-family: Arial, Helvetica, sans-serif;
}

body {
  max-width: 600px;
  margin: 0 auto;
}

form div {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 20px;
}

select,
textarea,
.translate-output {
  padding: 5px;
}

.translate-output {
  min-height: 150px;
  border: 1px solid black;
  width: 100%;
  display: block;
}

.error {
  color: red;
}

请注意,我们不会展示此示例的 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() 方法来监听两个事件:

  • submit 事件在 <form> 元素上触发;当表单提交时,调用 handleTranslation() 函数。
  • input 事件在 <textarea> 元素上触发;当当前 <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;
  } else {
    translateOutput.innerHTML = "";
  }

如果测试通过,我们打开一个 try { ... } 代码块。我们首先使用availability()”)方法检查模型是否可用,用于在检测到的输入语言和选择的输出语言之间进行翻译:

  • 如果返回unavailable,我们在具有类translate-output<p>中打印相应的错误消息。
  • 如果返回 available,我们使用 create()”) 方法创建翻译器,并传入检测到的输入语言和选择的输出语言。所需的 AI 模型可用,因此我们可以立即使用它。
  • 如果返回其他值(即 downloadabledownloading),我们调用相同的 create() 方法,但这次包含一个 monitor,该 monitor 会在每次触发 downloadprogress 事件触发时,打印出模型下载到 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>`;
  }
}
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 = "";

form.addEventListener("submit", handleTranslation);
textarea.addEventListener("input", detectLanguage);

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;
  }
}

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 {
    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;
    }
    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,
            )}%`;
          });
        },
      });
    }

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

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

    translateOutput.textContent = translation;
    submitBtn.disabled = false;
  } catch (e) {
    translateOutput.innerHTML = `<span class="error">${e}</span>`;
  }
}

结果

渲染后的示例如下:

图0:谷歌浏览器将提供内置翻译和语言检测 API

请在 <textarea> 中输入一段文本,并注意检测到的语言和置信度仅在字符数超过 20 时才会显示。选择与输入文本不同的翻译语言,然后点击提交按钮以生成 AI 翻译结果。

部分翻译语言选项可能在您的浏览器中不可用,即使该浏览器支持相关API。

浏览器支持

图1:谷歌浏览器将提供内置翻译和语言检测 API

 

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注