Language Detection Is a Decision, Not an Answer

Explain this chapter with AI

Copy this prompt into ChatGPT, Claude, Gemini, a local model, or another AI.

Apply this chapter with AI

Copy this prompt into ChatGPT, Claude, Gemini, a local model, or another AI.

Translation appears to be a two-step browser-AI pipeline:

text
  ↓
detect language
  ↓
translate to target language

The implementation is short enough to fit inside one event handler.

const candidates = await detector.detect(text);
const sourceLanguage = candidates[0].detectedLanguage;
const translator = await Translator.create({
  sourceLanguage,
  targetLanguage: "en"
});
const output = await translator.translate(text);

The dangerous line is not the model call.

It is the array index.

candidates[0] is the highest-ranked language returned by the detector. That does not make it correct, supported for translation, or confident enough to justify an automatic action.

This chapter is about the decision between the two APIs.


1. Detection returns a ranking

The Language Detector API returns candidates shaped like:

[
  { detectedLanguage: "de", confidence: 0.9993 },
  { detectedLanguage: "en", confidence: 0.0004 },
  { detectedLanguage: "nl", confidence: 0.0001 }
]

The list expresses relative evidence. The first item is the model’s best candidate among languages it can represent.

It does not express certainty in the everyday sense.

The detector is trained over a finite set of languages. The input may be too short, contain several languages, consist mainly of names or code, or belong to a language outside that set. A ranking model can still put something first when every candidate is poor.

The application needs a policy:

ranked candidates
      ↓
decision policy
      β”œβ”€β”€ select language
      β”œβ”€β”€ ask user
      └── abstain

Without that middle layer, uncertainty silently becomes a fact.


2. Short text is a different problem

Consider these inputs:

Gift
Chef
Chat
No

Each appears in multiple languages or has different meanings across them. A detector can return a ranking, but the evidence available in the input is weak.

Chrome’s documentation explicitly warns that very short phrases and single words produce low accuracy. A product that routinely receives short text should not treat the same threshold used for full paragraphs as adequate.

We can model the decision using both confidence and input evidence:

function chooseLanguage(candidates, text, {
  minimumConfidence = 0.8,
  minimumMargin = 0.2,
  minimumCharacters = 20
} = {}) {
  const [first, second] = candidates;
  const chars = [...text.trim()].length;

  if (!first || chars < minimumCharacters) {
    return { kind: "unknown", reason: "insufficient-text" };
  }

  if (first.confidence < minimumConfidence) {
    return { kind: "unknown", reason: "low-confidence" };
  }

  const margin = first.confidence - (second?.confidence ?? 0);
  if (margin < minimumMargin) {
    return { kind: "unknown", reason: "ambiguous-ranking" };
  }

  return {
    kind: "selected",
    language: first.detectedLanguage,
    confidence: first.confidence,
    margin
  };
}

The numeric defaults are hypotheses, not universal truths. They must be calibrated on the product’s input distribution.

The valuable architectural move is the explicit unknown state.


3. Confidence is not calibration

If a detector assigns confidence $0.9$ to one hundred cases, a calibrated score would imply that roughly ninety are correct under comparable conditions.

That property must be measured. It does not follow from the field being named confidence.

For a set of labelled examples, divide predictions into confidence bins and compare predicted confidence with empirical accuracy:

$$ \operatorname{ECE} = \sum_{b=1}^{B} \frac{|S_b|}{n} \left| \operatorname{acc}(S_b) - \operatorname{conf}(S_b) \right| $$
Expected calibration error is only one summary, and binning has limitations. The larger point is that the score needs empirical interpretation.

Browser AI Observatory should record:

  • the complete ranked candidate list;
  • selected candidate, if any;
  • policy thresholds;
  • abstention reason;
  • user correction, when available;
  • browser and environment metadata.

If we store only the selected language, we cannot later change the threshold and replay the decision.


4. Detection and translation have separate availability

A detector being available does not imply that every translation pair is available.

Translation requires an explicit source and target:

const options = {
  sourceLanguage: "de",
  targetLanguage: "en"
};

const availability = await Translator.availability(options);

The full pipeline needs two capability decisions:

    flowchart TD
    T[Input text] --> D[Detect candidates]
    D --> P{Policy selects?}
    P -->|No| U[Unknown or ask user]
    P -->|Yes| A{Pair available?}
    A -->|No| F[Explain or fallback]
    A -->|Yes| X[Translate]
  

The UI should distinguish:

  • language detection unavailable;
  • language detection uncertain;
  • translation pair unavailable;
  • translation model downloadable;
  • translation in progress;
  • translation failed;
  • translation completed but failed evaluation.

β€œTranslation failed” erases too much information to be useful.


5. Expert models have their own lifecycle

Language detection and translation use task-focused models managed by the browser. They may be smaller or have different acquisition behavior from the foundation model used by generative text APIs.

That means the user can encounter a second download even after successfully using the Prompt API.

The observatory records apiId and creation options on acquisition events:

{
  "type": "model.download.progress",
  "correlation": {
    "sessionId": "translator-de-en-01"
  },
  "data": {
    "apiId": "translator",
    "loaded": 0.62
  }
}

We should not label that event β€œGemini download” or assume one asset. The supported public fact is that the browser is acquiring what the requested capability requires.

This is another reason the API contract matters more than a guessed implementation detail.


6. Build the composed operation

A safer pipeline preserves each stage:

async function detectAndTranslate(text, targetLanguage, policy) {
  const detectorAvailability = await LanguageDetector.availability();
  if (detectorAvailability === "unavailable") {
    return { outcome: "unavailable", stage: "detection" };
  }

  const detector = await LanguageDetector.create();
  const candidates = await detector.detect(text);
  const decision = chooseLanguage(candidates, text, policy);

  if (decision.kind !== "selected") {
    return {
      outcome: "abstained",
      stage: "selection",
      decision,
      candidates
    };
  }

  if (decision.language === targetLanguage) {
    return {
      outcome: "unchanged",
      stage: "selection",
      decision,
      candidates,
      output: text
    };
  }

  const options = {
    sourceLanguage: decision.language,
    targetLanguage
  };
  const translatorAvailability = await Translator.availability(options);

  if (translatorAvailability === "unavailable") {
    return {
      outcome: "unavailable",
      stage: "translation",
      decision,
      candidates,
      options
    };
  }

  const translator = await Translator.create(options);
  const output = await translator.translate(text);

  return {
    outcome: "completed",
    stage: "translation",
    decision,
    candidates,
    options,
    output
  };
}

This function is longer than indexing the first candidate. The additional code represents real states that the shorter version ignored.


7. Run the language-routing laboratory

Select Run with Browser AI from Chapter 08 to open:

/tools/ai/browser-ai-from-first-principles/08-chapter/

The laboratory turns the composed operation into three visible stages:

  1. inspect and prepare Language Detector;
  2. detect a complete ranked list and apply the policy;
  3. only after selection, inspect and prepare the exact Translator pair.

The default policy requires reported confidence of at least (0.8) and a first–second margin of at least (0.2). Both inputs are editable because they are product hypotheses, not properties guaranteed by the API. Changing either threshold reruns the decision against the retained candidate list. It does not rerun the model or silently discard evidence.

Two canonical fixtures are available. The German detector fixture expects de to rank first before routing to English. The English-to-French fixture reuses the sentence whose protected relation assigns model responsibility to the browser and experience responsibility to the application.

The expected source language belongs only to evaluation. It never overrides the live detector:

live candidates β†’ visible policy β†’ selected source or abstention
fixture label   ─────────────────→ evaluation only

If confidence or margin fails, the decision card says Abstain, the Translator controls remain disabled, and the trace records the reason. No pair is inspected, no translation asset is requested, and no local result is presented. This is a successful policy outcome, not an API failure.

When the policy selects a source, translation still does not begin. The reader must inspect Translator.availability({ sourceLanguage, targetLanguage }) and explicitly prepare that pair. This separation makes a second download, an unsupported pair, or a creation failure attributable to the translation stage rather than to detection.

Each stage emits the same versioned Observatory event schema used by earlier chapters. Detector completion retains the ranked list and policy inputs; selection emits feature.validation.finished; Translator events carry the chosen pair. Exported traces can therefore distinguish:

  • a detector that was absent;
  • a detector that ran but produced ambiguous evidence;
  • a selected language whose pair was unavailable;
  • a prepared pair whose translation failed;
  • a completed translation whose semantic review remains unresolved.

The translation fixture includes narrow automatic checks and a human rubric. A successful promise proves operational completion only. It does not prove that contrast, negation, quantities or responsibility survived the transformation.

The reviewed September 2 replay contains Prompt API capability and session events, but no Language Detector or Translator events. Replay mode reports that absence instead of presenting Prompt evidence as if the routing pipeline had already run.


8. Mixed-language input breaks the single-label assumption

Real browser text is frequently multilingual:

The deployment failed with Speicher nicht ausreichend, so the model could not load.

One language label cannot describe every span. The detector may choose the dominant language, the language with the strongest signal, or another candidate based on its training.

Before translating, decide the unit of text:

  • whole document;
  • paragraph;
  • sentence;
  • user-selected span;
  • message.

Smaller units isolate language changes but reduce contextual evidence. Larger units provide more evidence but can mix languages.

This is a segmentation problem before it is a detection problem.

The observatory fixture uses a complete German sentence rather than one word precisely to test the API under a reasonable evidence condition. Later fixtures should add mixed-language text, product names, code, URLs and unsupported languages.


9. Translation is ordered and stateful at the resource level

Chrome documents that translations submitted to one translator are processed sequentially. A long request can block later work.

That changes UI and scheduling design.

If a page translates fifty independent messages, firing fifty calls at once does not guarantee fifty-way parallelism. The application should expose queue state, allow cancellation where supported, and avoid placing a tiny urgent request behind an enormous background translation.

translator instance
  β”œβ”€β”€ request 1: running
  β”œβ”€β”€ request 2: queued
  └── request 3: queued

Possible policies include:

  • one translator per language pair with a visible FIFO queue;
  • bounded independent instances for interactive and batch work;
  • chunking long text with ordered reassembly;
  • admission control that prevents unbounded queues.

The best choice depends on resource costs we have not yet measured. The important point is that an asynchronous API does not imply unconstrained parallel execution.


10. Translation quality is relational

A fluent target-language sentence can still fail by:

  • changing negation;
  • changing quantities or dates;
  • translating a product name;
  • dropping a technical term;
  • changing who performed an action;
  • weakening β€œmust” into β€œmay”;
  • inventing an explanation absent from the source.

Our first fixture translates:

The browser manages the model, but the application manages the experience.

The protected relation is contrast:

browser β†’ model responsibility
application β†’ experience responsibility

A reference translation can help, but lexical overlap with one reference is not a complete metric. Multiple correct translations can express the relation differently.

Useful checks include:

  • named-term preservation;
  • number and punctuation preservation where appropriate;
  • round-trip diagnostics;
  • bilingual human review;
  • task-specific relational assertions;
  • downstream task success.

Round-trip translation is a diagnostic, not proof. Two lossy transformations can return a plausible source sentence while both missing the original nuance.


11. The detector fixture needs a ranked assertion

A lexical check for the code de is not sufficient. It could pass when German appears fifth, and the substring even appears inside the field name detectedLanguage.

The Observatory evaluator therefore parses the result array and uses a task-specific assertion:

{
  kind: "top-language",
  value: "de",
  minimumConfidence: 0.8,
  minimumMargin: 0.2
}

The assertion checks three claims independently: German ranks first, its reported confidence crosses the provisional threshold, and it is sufficiently separated from the second candidate.

The thresholds still require calibration on real inputs. The improvement is that the test now measures the property it names instead of searching serialized text for two characters.


12. Preserve user correction as evidence

When the detector abstains or chooses incorrectly, the user may select the source language manually.

That correction is valuable evidence:

{
  "type": "feature.validation.finished",
  "data": {
    "feature": "language-selection",
    "accepted": false,
    "predicted": "nl",
    "selectedByUser": "de",
    "inputClass": "short-message"
  }
}

Do not automatically turn these records into training data. They may contain sensitive content, accidental selections or distribution bias. They can still support local evaluation and threshold calibration under an explicit retention policy.

The first use is diagnosis: which input classes cause uncertainty or correction?


13. Local translation still has a data boundary

Client-side detection and translation can keep ephemeral text on the device for those operations. This is valuable for support messages, draft content and page selections.

The complete product may still transmit the translated result. An application may log the source. An extension may export a trace. A cloud fallback may activate when a pair is unavailable.

The interface should state the route:

Detected locally
Translated locally
Result will be sent when you submit this form

If fallback changes the route, the user should know before sensitive text moves.

Local execution improves a segment of the data flow. Privacy remains a property of the whole system.


Conclusion

Language detection is not an answer. It is evidence for a decision.

The detector returns a ranked list over supported candidates. The application must decide whether the text is sufficient, whether confidence and separation justify selection, whether the translation pair is available, and whether to translate, ask or abstain.

Translation then introduces its own model lifecycle, pair configuration, queue behavior and relational evaluation. A successful target-language string does not prove that the source meaning survived.

This completes the first task-API group. Browser AI Observatory can now exercise seven capability surfaces through one lifecycle while preserving task-specific fixtures. Chapter 08 makes the boundary between those surfaces executable: ranked detector evidence, application policy and pair-specific translation remain separate states in one trace.

The next part moves beneath individual calls. We will study sessions, context capacity, cold starts, warm runs, model management and the experimental question that started the book: what changes when the browser replaces the model behind a stable application boundary?


Sources and further reading

  1. Chrome for Developers, Language detection with built-in AI.
  2. Chrome for Developers, Translation with built-in AI.
  3. Chrome for Developers, Get started with built-in AI.
  4. Chrome for Developers, Understand built-in model management in Chrome.