You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Input formats for translation and language detection #60
While the spec doesn't seem to say anything about supported formats, in practice, inputting HTML seems to work just fine (and surprisingly fine even) for translations:
consttranslator=awaitTranslator.create({sourceLanguage: 'en',targetLanguage: 'es',});awaittranslator.translate('<p>Hello, or should I say <strong>good morning</strong>?</p>');// '<p>Hola, o debería decir <strong>Buenos días</strong>?</p>'
However, the same can't be said for language detection:
Test-wise stripping the HTML from the input string correctly results in the language to be detected as German.
Do we need something like SummarizerFormat but for the Translator and Language Detector APIs to, for example, set expectations that corresponding words like the <strong>good morning</strong> would also be contained in the output (<strong>Buenos días</strong>) and to make sure the developer doesn't need to do an innerText dance to strip HTML formatting for language detection?
The three to-be-supported formats ideally would be the same as for the Writing Assistance APIs, that is, plain text and Markdown.
As a developer, I'd also wish for direct HTML support, as this avoids a to-Markdown dance, which may lose styling like classes that were in the original HTML.
One idea would be to add a mimeType parameter to the options bag that would allow the API to enter into a safe mode where it sanitizes when the input is HTML. If developers send HTML without the proper MIME type, the API could escape the HTML automatically in such cases to make it harmless. Another option would be to simply use a DOM tree as the input. In all cases proper sanitizing would be needed, but we have the Sanitizer API now.
That shouldn't be the case if the transform is DOM-to-DOM. We would need to specify which content is expected to be handled by the translator, but otherwise it shouldn't create new elements, change element types, or change attribute values that are not intended to be human-readable.
In our existing translation pipeline using LLMs, we have issues with interpolation (similar to HTML tags).
Something like hello world #{count} might translate as Hallo Welt #{wortzahl} or even just Hallo Welt {wortzahl} (broken syntax). This is an issue with variable interpolation, but an LLM would have the same problem with HTML tags too.
This could be left to the developer to cleanup afterwards, or handled by the browser. But good if the spec is clear on what guarantees are given with regards to html tags, i.e. does it guarantee that tags or might them be broken.
Yeah, that's a good point. I'm hoping that we could define a system where if the system was fed the DOM:
<p>hello world <spanclass="count">0</span></p>
…then it would know not to change the class attribute value, although it may change title attribute values. If we would have it preserve the span element, even better.
But the important thing is we define the expectations, so the result is interoperable, even if the human language part of the translation is subjective.
That's a good point. Other attributes like aria-label come to mind, too. There's likely someone (you, @jakearchibald?) who knows by heart all the ones that would qualify.
I don't know them off the top of my head, but it should be an allow-list defined by the spec.
There are some tricky edge cases where content is displayed to the user but isn't in the DOM tree. Such as input values and pseudo elements. I guess shadow DOM would need to be taken into consideration too, but there are patterns for that already.
One idea would be to add a mimeType parameter to the options bag that would allow the API to enter into a safe mode where it sanitizes when the input is HTML. If developers send HTML without the proper MIME type, the API could escape the HTML automatically in such cases to make it harmless. Another option would be to simply use a DOM tree as the input. In all cases proper sanitizing would be needed, but we have the Sanitizer API now.
I like the idea of setting the mimeType to text/html might make the translator behave differently, but IMO automatically doing any transformation to the input when the mimetype is set to text/plain would be unhelpful and confusing. If I tell the API to treat my input as plain text it should do just that. What happens if my input happens to include text that looks like HTML? Like the string "Is Foo / Bar > Alice & Bob?", it would be strange to have the response HTML encoded. I might be outputting the API response into a form field rather than injecting it into the DOM where the escaped characters wouldn't be unescaped and rendered.
If input needs to be sanitised before it can be translated then developers should have the tools to do that before calling the Transformation API, rather than making assumptions on the "simple" text/plain code path.
The fact that browsers have built-in page translation features seems to indicate that "translate the human-readable content of the DOM without changing the machine-readable content" is a solved problem and is what we want here. As I see it there would be two versions of this API: one which is string-to-string and can be used for general-purpose translation of human-readable text and one which is (HTMLElement or TrustedHTML)-to-TrustedHTML which is used for translating content that intended to be used with an HTML sink. We can't stop developers from passing HTML to the text-to-text API but we can provide a safe alternative which, by integrating with Trusted Types, would be easier to use.
Another approach to solve the hassle of html in translations, might be to just raise an exception if any <, >, & etc character is detected. And let developers clean them out ahead of time (a simple fix is to replace them with unicode-equivalents).
That would fairly clearly signal that it's not supposed to be used for translating raw HTML, thereby side-stepping the security issues around that use-case.
I think in practice, translating raw HTML isn't a major use-case anyway.
That's a good point. Other attributes like aria-label come to mind, too. There's likely someone (you, @jakearchibald?) who knows by heart all the ones that would qualify.
@jakearchibald
I don't know them off the top of my head, but it should be an allow-list defined by the spec.
There are some tricky edge cases where content is displayed to the user but isn't in the DOM tree. Such as input values and pseudo elements. I guess shadow DOM would need to be taken into consideration too, but there are patterns for that already.
There are some attributes that are defined as translatable by the HTML spec:
"Other specifications may define other attributes that are also translatable attributes. For example, ARIA would define the aria-label attribute as translatable."
The ARIA spec does define its own translatable attributes here:
In general, I see value in having both a plain-text API and a DOM-to-DOM API.
The former is much more straightforward, and will likely be sufficient for a vast number of use cases.
However, I share the concern that if a plain-text API is the only API that exists, then it opens the door to be used in alarming ways with no reasonable alternative, such as this example that Jake brought up in another thread.
Thanks all for the discussion here and in mozilla/standards-positions#1015. We seem to be circling because this issue bundles several independent questions, and comments tend to answer different ones. This comment tries to (a) separate them, (b) agree evaluation criteria, and (c) propose a concrete set of decisions to react to in separate issues. If there are no sustained objections by 1 Month, I'll land these as provisional and we'll iterate via PR.
Provisional / non-blocking: interpolation-placeholder preservation (@sandstrom) is not a v1 guarantee for free-text input; DOM-to-DOM naturally protects real tags, but placeholder tokens embedded in text are a documented known limitation for now.
Editorial note: this is a proposal for the group to shoot at, not a decision. Please object explicitly to any decision (explictely mentioned in the bottom of this comment, as separate threads).
Use cases (inferred from this thread)
Translate a rich-text snippet while preserving inline structure (e.g. <strong>, links) and author intent (class, id, aria-*).
Translate user-generated / untrusted content without creating an injection sink.
Detect the language of a string that may contain markup, without the developer doing an innerText dance.
Don't damage interpolation placeholders (e.g. #{count}): raised by @sandstrom as a real LLM failure mode that also applies to tags.
Evaluation criteria
Determinism & interop: behavior is defined, not "whatever the model tolerates."
Safety: the design does not add a new injection surface.
Preserves author intent: non-human-readable attributes and structure survive.
Simplicity: smallest thing that meets the use cases (avoid scope creep).
Feature-detectable: authors can detect support and fall back.
Consistency with the Writing Assistance APIs.
What I need from reviewers
Here are the questions we're actually deciding (derived from the threat). I'd like us to resolve these in order and separately, rather than voting on a whole API shape at once.
However, the presence of HTML tags can skew language detection especially when the tag name is valid English. For example - <strong>Guten Morgen</strong><strong></strong><strong></strong><strong></strong> is classified as English. <div>Guten Morgen</div><div></div><div></div><div></div> is classified as German.
For translation I agree there is a primitive that is missing in the API to represent a sequence of text in the same translation context that needs to be translated. My issue #85 is asking about collection of text with different translation context which is a counterpart to this.
For input text like I ran <b>out</b> of time., without this primitive a web developer is left having to translate each chunk independently resulting in
translate("I ran ") → "Ich rannte "
translate("out") → "hinaus"
translate(" of time.") → " der Zeit."
instead of "Mir ging die Zeit aus."
Therefore, it does seem to me that we should support HTML as input type for both APIs where the browser performs requisite preprocessing/post processing, to retain the words and separators in context.
Now thinking about this a bit broader for a use case where a web developer wants to translate markdown
Please turn off the light.
the same problems as with HTML reappear.
So instead of supporting HTML as input, I think accepting a collection of strings may be a better choice in this case. I did want to use a collection of strings as the API shape for batched inputs, if we go down this path - we need to figure out how to represent these two concepts at the API level - Sequence of same context text (processed together for semantic context), Sequence of independent context text (batched for performance).
Activity
domenic commentedon Sep 13, 2025
It'd be neat if we could mandate that all implementations support HTML and Markdown. In particular if Chrome could fix their language detection.
But otherwise, I agree that a supported formats input at the spec level is probably the way to solve this.
tomayac commentedon Jan 27, 2026
Some good discussion with @jakearchibald over on mozilla/standards-positions#1015 (starting at mozilla/standards-positions#1015 (comment)) about this feature request.
One idea would be to add a
mimeTypeparameter to the options bag that would allow the API to enter into a safe mode where it sanitizes when the input is HTML. If developers send HTML without the proper MIME type, the API could escape the HTML automatically in such cases to make it harmless. Another option would be to simply use a DOM tree as the input. In all cases proper sanitizing would be needed, but we have the Sanitizer API now.jakearchibald commentedon Jan 27, 2026
That shouldn't be the case if the transform is DOM-to-DOM. We would need to specify which content is expected to be handled by the translator, but otherwise it shouldn't create new elements, change element types, or change attribute values that are not intended to be human-readable.
sandstrom commentedon Jan 27, 2026
Just a small data point from a developer.
In our existing translation pipeline using LLMs, we have issues with interpolation (similar to HTML tags).
Something like
hello world #{count}might translate asHallo Welt #{wortzahl}or even justHallo Welt {wortzahl}(broken syntax). This is an issue with variable interpolation, but an LLM would have the same problem with HTML tags too.This could be left to the developer to cleanup afterwards, or handled by the browser. But good if the spec is clear on what guarantees are given with regards to html tags, i.e. does it guarantee that tags or might them be broken.
jakearchibald commentedon Jan 27, 2026
Yeah, that's a good point. I'm hoping that we could define a system where if the system was fed the DOM:
…then it would know not to change the class attribute value, although it may change title attribute values. If we would have it preserve the span element, even better.
But the important thing is we define the expectations, so the result is interoperable, even if the human language part of the translation is subjective.
tomayac commentedon Jan 27, 2026
That's a good point. Other attributes like
aria-labelcome to mind, too. There's likely someone (you, @jakearchibald?) who knows by heart all the ones that would qualify.jakearchibald commentedon Jan 27, 2026
I don't know them off the top of my head, but it should be an allow-list defined by the spec.
There are some tricky edge cases where content is displayed to the user but isn't in the DOM tree. Such as input values and pseudo elements. I guess shadow DOM would need to be taken into consideration too, but there are patterns for that already.
xM8WVqaG commentedon Jan 27, 2026
(this is also a reply to mozilla/standards-positions#1015, as this line of discussion appears to have migrated to this issue).
I like the idea of setting the mimeType to
text/htmlmight make the translator behave differently, but IMO automatically doing any transformation to the input when the mimetype is set totext/plainwould be unhelpful and confusing. If I tell the API to treat my input as plain text it should do just that. What happens if my input happens to include text that looks like HTML? Like the string"Is Foo / Bar > Alice & Bob?", it would be strange to have the response HTML encoded. I might be outputting the API response into a form field rather than injecting it into the DOM where the escaped characters wouldn't be unescaped and rendered.If input needs to be sanitised before it can be translated then developers should have the tools to do that before calling the Transformation API, rather than making assumptions on the "simple"
text/plaincode path.reillyeon commentedon Jun 2, 2026
The fact that browsers have built-in page translation features seems to indicate that "translate the human-readable content of the DOM without changing the machine-readable content" is a solved problem and is what we want here. As I see it there would be two versions of this API: one which is string-to-string and can be used for general-purpose translation of human-readable text and one which is (HTMLElement or TrustedHTML)-to-TrustedHTML which is used for translating content that intended to be used with an HTML sink. We can't stop developers from passing HTML to the text-to-text API but we can provide a safe alternative which, by integrating with Trusted Types, would be easier to use.
sandstrom commentedon Jun 3, 2026
Another approach to solve the hassle of html in translations, might be to just raise an exception if any
<,>,&etc character is detected. And let developers clean them out ahead of time (a simple fix is to replace them with unicode-equivalents).That would fairly clearly signal that it's not supposed to be used for translating raw HTML, thereby side-stepping the security issues around that use-case.
I think in practice, translating raw HTML isn't a major use-case anyway.
toreini commentedon Jun 4, 2026
there have been some discussions with @nordzilla which might be good to have his opinion here.
nordzilla commentedon Jun 4, 2026
@toreini thanks for the ping. I'm catching up on this thread.
There are some attributes that are defined as translatable by the HTML spec:
This list is non-exhaustive. It says:
The ARIA spec does define its own translatable attributes here:
Firefox attempts to abide by these specs, and its implementation at the time of writing is here:
In general, I see value in having both a plain-text API and a DOM-to-DOM API.
The former is much more straightforward, and will likely be sufficient for a vast number of use cases.
However, I share the concern that if a plain-text API is the only API that exists, then it opens the door to be used in alarming ways with no reasonable alternative, such as this example that Jake brought up in another thread.
toreini commentedon Aug 19, 2026
Proposed resolution / Call for consensus
Thanks all for the discussion here and in mozilla/standards-positions#1015. We seem to be circling because this issue bundles several independent questions, and comments tend to answer different ones. This comment tries to (a) separate them, (b) agree evaluation criteria, and (c) propose a concrete set of decisions to react to in separate issues. If there are no sustained objections by 1 Month, I'll land these as provisional and we'll iterate via PR.
Provisional / non-blocking: interpolation-placeholder preservation (@sandstrom) is not a v1 guarantee for free-text input; DOM-to-DOM naturally protects real tags, but placeholder tokens embedded in text are a documented known limitation for now.
Editorial note: this is a proposal for the group to shoot at, not a decision. Please object explicitly to any decision (explictely mentioned in the bottom of this comment, as separate threads).
Use cases (inferred from this thread)
<strong>, links) and author intent (class,id,aria-*).innerTextdance.#{count}): raised by @sandstrom as a real LLM failure mode that also applies to tags.Evaluation criteria
What I need from reviewers
Here are the questions we're actually deciding (derived from the threat). I'd like us to resolve these in order and separately, rather than voting on a whole API shape at once.
mimeTypetag*, or a *structured DOM-to-DOM* transform? #82sushraja-msft commentedon Aug 31, 2026
On the topic of supporting HTML in language detection.
In the case of Edge, language detection performs preprocessing that removes tags like <,> so for the example
<strong>Guten Morgen</strong>, we do detect German 75%.https://microsoftedge.github.io/Demos/built-in-ai/playgrounds/languagedetector-api/
However, the presence of HTML tags can skew language detection especially when the tag name is valid English. For example -
<strong>Guten Morgen</strong><strong></strong><strong></strong><strong></strong>is classified as English.<div>Guten Morgen</div><div></div><div></div><div></div>is classified as German.For translation I agree there is a primitive that is missing in the API to represent a sequence of text in the same translation context that needs to be translated. My issue #85 is asking about collection of text with different translation context which is a counterpart to this.
For input text like
I ran <b>out</b> of time., without this primitive a web developer is left having to translate each chunk independently resulting intranslate("I ran ") → "Ich rannte "
translate("out") → "hinaus"
translate(" of time.") → " der Zeit."
instead of "Mir ging die Zeit aus."
Therefore, it does seem to me that we should support HTML as input type for both APIs where the browser performs requisite preprocessing/post processing, to retain the words and separators in context.
Now thinking about this a bit broader for a use case where a web developer wants to translate markdown
Please turn off the light.
the same problems as with HTML reappear.
So instead of supporting HTML as input, I think accepting a collection of strings may be a better choice in this case. I did want to use a collection of strings as the API shape for batched inputs, if we go down this path - we need to figure out how to represent these two concepts at the API level - Sequence of same context text (processed together for semantic context), Sequence of independent context text (batched for performance).