v3.0.0

<bmx-translation-editor>

A localisation workbench: open a translation file - XLIFF 1.2 or 2.x, gettext PO or POT, an Apple String Catalog - or a one-language source file with its translation (Android strings.xml, Apple .strings, JSON message files, Flutter ARB, .NET .resx), translate string by string with source and translation side by side, and save the file back in its own format with only the translated strings changed.

32 properties · 4 events · 17 methods · 12 parts

Example

Try it with your own files in confidence: they are opened by your browser, on your device. Nothing is uploaded, no copy reaches us or anyone else, and nothing is kept once you close this tab.

Reading...

Show markup
<bmx-translation-editor id="ex-tr" label="Polish translation" description="A gettext file part way through: one string needs review, one has lost a placeholder, and Polish needs three plural forms where English has two. The memory and glossary below are loaded too."></bmx-translation-editor>
<p class="note" id="ex-tr-out" role="status" style="margin: 12px 0 0">Reading...</p>

<script type="module">
  await customElements.whenDefined('bmx-translation-editor');
  const editor = document.getElementById('ex-tr');
  const out = document.getElementById('ex-tr-out');

  // A made-up booking app's Polish catalogue.
  const po = `# Polish translation of the Harbour Lane booking app.
msgid ""
msgstr ""
"Project-Id-Version: harbour-lane 3.2\\n"
"Language: pl\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2);\\n"

#. Heading on the bookings page
#: src/bookings/list.html:4
msgid "Your bookings"
msgstr "Twoje rezerwacje"

#: src/bookings/list.html:12
#, c-format
msgid "%d booking this week"
msgid_plural "%d bookings this week"
msgstr[0] "%d rezerwacja w tym tygodniu"
msgstr[1] ""
msgstr[2] ""

#. %s is the guest's name
#: src/bookings/card.html:8
#, c-format
msgid "Booked by %s on %s"
msgstr "Zarezerwowane przez %s"

#: src/bookings/card.html:21
#, fuzzy
#| msgid "Cancel the booking"
msgid "Cancel this booking"
msgstr "Anuluj rezerwację"

#: src/bookings/card.html:22
msgid "Change the booking"
msgstr ""

#: src/account/menu.html:3
msgid "Account settings"
msgstr ""

#: src/account/menu.html:9
msgid "Sign out"
msgstr "Wyloguj się"

#. Shown after a booking is paid for
#: src/pay/done.html:2
msgid "Thank you! Your booking is confirmed."
msgstr ""
`;

  // Earlier translations from the team's memory, and its glossary.
  const tmx = `<?xml version="1.0" encoding="UTF-8"?>
<tmx version="1.4">
  <header creationtool="example" creationtoolversion="1" segtype="sentence" o-tmf="example" adminlang="en" srclang="en" datatype="plaintext"/>
  <body>
    <tu><tuv xml:lang="en"><seg>Change the booking details</seg></tuv><tuv xml:lang="pl"><seg>Zmień szczegóły rezerwacji</seg></tuv></tu>
    <tu><tuv xml:lang="en"><seg>Thank you! Your order is confirmed.</seg></tuv><tuv xml:lang="pl"><seg>Dziękujemy! Twoje zamówienie zostało potwierdzone.</seg></tuv></tu>
    <tu><tuv xml:lang="en"><seg>Account settings</seg></tuv><tuv xml:lang="pl"><seg>Ustawienia konta</seg></tuv></tu>
  </body>
</tmx>`;
  const glossary = `en,pl,forbidden
booking,rezerwacja,
booking,booking,yes
account,konto,`;

  editor.glossary = glossary;
  await editor.addMemory(tmx, 'team.tmx');
  await editor.load({ target: { name: 'po/pl.po', text: po } });

  const report = async () => {
    const issues = (await editor.getIssues()).filter(i => i.severity === 'error');
    const p = await editor.getProgress();
    const done = p.byState.translated.units + p.byState.approved.units;
    out.textContent = `${done} of ${p.units} strings translated; ${issues.length ? `${issues.length} error${issues.length === 1 ? '' : 's'} to fix` : 'no errors'}.`;
  };
  // The checks run a moment after each change.
  editor.addEventListener('bmxUnitChange', () => setTimeout(report, 200));
  await report();
</script>
<bmx-translation-editor label="French translation"></bmx-translation-editor>
<script>
  editor.load({ target: { name: 'fr.po', text: poText } });
</script>

Inline markup - XLIFF tags, Android <b> and <xliff:g> - shows as numbered tokens (⟨1⟩ ⟨/1⟩ ⟨2/⟩) that can be inserted but not broken; placeholders (%s, %1$@, {name}, {{count}}) are marked; plural strings get one field per plural form the target language has, labelled with the numbers that take it; ICU messages are previewed with sample values in the target language; right-to-left languages are edited right to left.

A translation memory (TMX files, plus every string confirmed in the session) offers earlier translations with a score and what differs, with changed numbers already put right; a glossary (TBX or CSV) marks its terms in the source and says how to translate them. Checks run as you type: placeholders and tags kept, ICU syntax and plural categories, empty forms, numbers, length limits, spacing, ending punctuation, glossary terms.

Nothing leaves the page: files are read in the browser, and saving downloads the file (or, cancelling bmxSave, hands its text and bytes to the page). In a form, name receives the translated file's text.

Keyboard in a translation: Ctrl+Enter confirms and moves to the next string to do, Alt+Up/Down moves to the previous or next string, Ctrl+Insert copies the source, F9 inserts the next tag or placeholder the translation lacks, Ctrl+Shift+1 to 9 use a memory match. In the list: arrows, Home/End, Page Up/Down, and Enter to edit.

Properties

PropertyAttributeTypeDefaultDescription
allowOpen allow-open boolean true Offer opening files (the Open button and dropping files).
allowSave allow-save boolean true Offer saving (the Save button).
description description string — Help text below the editor.
disabled disabled boolean false Disable the editor.
disabledChecks disabled-checks BmxL10nCheck[] | string — Checks to leave out, as an array, JSON or a comma list (numbers, punctuation).
errorText error-text string — An error supplied by the page.
filter filter BmxTranslationFilter 'all' Which strings the list shows. Two-way.
format format BmxL10nFormat — The format, when names and content do not say.
glossary glossary string | BmxGlossary — A glossary: TBX or CSV text, or one read with readGlossary.
glossarySrc glossary-src string — An address of a TBX or CSV glossary.
hideLabel hide-label boolean false Hide the label visually while keeping it as the accessible name.
hideToolbar hide-toolbar boolean false Hide the toolbar.
label label string — The field's label: names the whole control.
memory memory string | BmxTmEntry[] — A translation memory: TMX text, or entries.
memorySrc memory-src string — An address of a TMX file to load into the memory.
minMatch min-match number 70 The lowest memory match score shown (0-100).
name name string — The field's name in a form: it receives the translated file's text.
propagate propagate boolean true On confirming a string, fill the empty strings with the same source with the same translation.
readonly readonly boolean false Allow reading, searching and copying, but not changing.
requireComplete require-complete boolean false Keep the form from submitting until every string is translated.
requireValid require-valid boolean false Keep the form from submitting while a check finds an error.
search search string '' Text to search for in source, translation and key. Two-way.
source source string — A one-language format's source-language file.
sourceLanguage source-language string — The source language, when the file does not say.
sourceName source-name string — The source file's name.
sourceSrc source-src string — An address to load a one-language format's source file from.
src src string — An address to load the translation file from (the page's own server).
strings strings Partial<BmxTranslationEditorStrings> | string — Words to show instead of the English ones, as an object or JSON.
target target string — The translation file's text: a bilingual file (XLIFF, PO, String Catalog), or a one-language format's translated file.
targetLanguage target-language string — The language translated into: a String Catalog's language, or a new one-language translation's. Two-way.
targetName target-name string — The translation file's name (it tells the format and language, and names the saved file).
user user string — Who is translating, kept with the memory entries made here.

Events

EventDetailDescription
bmxLoad BmxTranslationLoadDetail Fired after a file is read.
bmxSave BmxTranslationSaveDetail Fired before the file is downloaded. Cancel it to save the text yourself.
bmxSelect BmxTranslationSelectDetail Fired when another string is selected.
bmxUnitChange BmxTranslationUnitDetail Fired after a string's translation or state changes.

Methods

MethodSignatureDescription
addMemory addMemory(memory: string | readonly BmxTmEntry[], origin?: string) => Promise<number> Add translations to the memory: TMX text or entries. Returns how many were added.
getChangeCount getChangeCount() => Promise<number> How many strings changed since the file was read or saved.
getDocument getDocument() => Promise<BmxL10nDocument | null> The document: its units with their translations and states.
getIssues getIssues() => Promise<BmxL10nIssue[]> Every problem the checks find now.
getMemory getMemory() => Promise<string> The memory's entries (loaded, and confirmed here), as TMX.
getProgress getProgress() => Promise<ReturnType<typeof documentProgress> | null> Units and words by state.
getText getText() => Promise<string> The translated file's text, written in its format (only translated strings changed).
load load(options: BmxTranslationLoadOptions) => Promise<BmxTranslationLoadDetail | null> Read a translation: { target } for a bilingual file, { source, target? } for a one-language format (with targetLanguage for a new translation).
loadFiles loadFiles(files: readonly File[] | FileList) => Promise<BmxTranslationLoadDetail | null> Read files the person chose or dropped: translation files, and TMX memories and TBX or CSV glossaries among them.
pretranslate pretranslate() => Promise<number> Fill empty strings from 100% memory matches. Returns how many were filled.
pseudoTranslate pseudoTranslate() => Promise<number> Fill empty strings with a pseudo-translation, to test a user interface. Returns how many.
redo redo() => Promise<boolean>
save save(fileName?: string) => Promise<boolean> Download the translated file (cancel bmxSave to handle it yourself).
selectUnit selectUnit(id: string) => Promise<boolean> Select a string by its id.
setGlossary setGlossary(glossary: string | BmxGlossary | null, fileName?: string) => Promise<void> Use a glossary: TBX or CSV text (with a file name to tell which), or one read with readGlossary.
setTranslation setTranslation(id: string, target: string | Record<string, string>, state?: BmxL10nState) => Promise<boolean> Change a string's translation (and state) as if typed, with undo.
undo undo() => Promise<boolean>

Slots

SlotDescription
description Rich help text, in place of the description property.
label Rich label content, in place of the label property.

CSS shadow parts

PartDescription
description The help text under the field.
label The label element.
list The list of strings.
menu The More menu.
progress The progress bar.
row A string in the list; also row-selected.
side The memory, terms, checks and preview panel.
source The source text.
status The bar under the editor.
target A translation field.
toolbar The bar of commands and filters.
unit The selected string's source, translation and state.

CSS custom properties

PropertyDescription
--bmx-translation-editor-background The editor's background.
--bmx-translation-editor-height The height of the list and editor on a wide screen.
--bmx-translation-editor-label-font-size The label's font size.
--bmx-translation-editor-list-height The list's height on a narrow screen, where the editor sits under it.
--bmx-translation-editor-placeholder-background Placeholders such as %s and {name}.
--bmx-translation-editor-placeholder-color Placeholders' text.
--bmx-translation-editor-radius Corner radius of the frame.
--bmx-translation-editor-row-height The height of one string in the list.
--bmx-translation-editor-selected-background The selected string in the list.
--bmx-translation-editor-support-font-size Font size of the description and error message.
--bmx-translation-editor-tag-background Inline tag tokens.
--bmx-translation-editor-tag-color Inline tag tokens' text.
--bmx-translation-editor-term-color The underline of glossary terms.