Skip to main content
Light Dark System

Translations

<zn-translations> | ZnTranslations
Since 1.0 experimental

Collects one piece of text in several languages, one language at a time.

The Translations component provides a user-friendly interface for managing multi-language text input. A select above the field chooses the language being edited, and each language it offers carries a chip saying whether it has a translation of its own or falls back to English; closed, it carries how many languages are done as a 1/5 chip. The field itself is a plain input, or a textarea with input-type="textarea".

Several fields that should share one language picker belong in a zn-translation-group instead.

<zn-translations
  languages='{"en":"English","fr":"French","de":"German"}'
  values='{"en":"Welcome","fr":"Bienvenue","de":"Willkommen"}'
></zn-translations>

Examples

Basic Usage

A simple translations component with default English language.

<zn-translations></zn-translations>

With Label

Use the label attribute to add a descriptive label above the translations.

<zn-translations
  label="Product Description"
  languages='{"en":"English","fr":"French"}'
></zn-translations>

Label Slot

Use the label slot for rich HTML content in the label.

Description
<zn-translations languages='{"en":"English","fr":"French"}'>
  <span slot="label">
    <strong>Description</strong>
    <zn-icon src="translate" size="16" style="margin-inline-start: 4px;"></zn-icon>
  </span>
</zn-translations>

Setting Values

values takes an object keyed by language code. value is the same thing as a JSON string, for setting it from markup or from a server-rendered template — set one or the other, not both.


<zn-translations
  label="Set with values"
  languages='{"en":"English","fr":"French","es":"Spanish"}'
  values='{"en":"Hello World","fr":"Bonjour le monde","es":"Hola Mundo"}'
></zn-translations>
<br />
<zn-translations
  label="Set with value"
  languages='{"en":"English","fr":"French"}'
  value='{"en":"This is a product description","fr":"Ceci est une description de produit"}'
></zn-translations>

Disabled State

Disable editing of translations.

<zn-translations
  label="System Message (Read-only)"
  disabled
  languages='{"en":"English","fr":"French"}'
  values='{"en":"This cannot be edited","fr":"Cela ne peut pas être modifié"}'
></zn-translations>

Flush Layout

Remove padding for a more compact appearance.

<zn-translations
  flush
  languages='{"en":"English","fr":"French","de":"German"}'
  values='{"en":"Compact layout","fr":"Mise en page compacte","de":"Kompaktes Layout"}'
></zn-translations>

Textarea

Use input-type="textarea" for longer copy, and textarea-rows to set its height.

<zn-translations
  label="Confirmation Message"
  input-type="textarea"
  textarea-rows="3"
  languages='{"en":"English","de":"German"}'
  values='{"en":"Thanks — your order is on its way.","de":"Danke — Ihre Bestellung ist unterwegs."}'
></zn-translations>

Inline Editing

Add inline-edit to read the translation as text until it is clicked, through zn-inline-edit, rather than showing an input outright.

<zn-translations
  inline-edit
  label="Welcome Message"
  languages='{"en":"English","fr":"French"}'
  values='{"en":"Hello World","fr":"Bonjour le monde"}'
></zn-translations>

Many Languages

Each language becomes an option labelled Name (CODE) — or the code alone where the configured name already is the code. The select takes any number of them, and its listbox scrolls once the list is longer than the space below it.

<zn-translations
  label="International Content"
  languages='{"en":"English","fr":"French","de":"German","es":"Spanish","it":"Italian","pt":"Portuguese","ru":"Russian","zh":"Chinese","ja":"Japanese","ar":"Arabic","hi":"Hindi","ko":"Korean"}'
  values='{"en":"Hello","fr":"Bonjour","de":"Hallo","es":"Hola","it":"Ciao","pt":"Olá","ru":"Привет","zh":"你好","ja":"こんにちは","ar":"مرحبا","hi":"नमस्ते","ko":"안녕하세요"}'
></zn-translations>

Blank Languages Fall Back to English

A language you have not translated yet is marked English in the select rather than hidden, and its field shows the English text as a placeholder. Leave it blank and the English text is what gets used.

<zn-translations
  label="Product Name"
  languages='{"en":"English","fr":"French","de":"German","pl":"Polish"}'
  values='{"en":"Premium Wireless Headphones","de":"Premium kabellose Kopfhörer"}'
></zn-translations>

RTL Language Support

The component automatically detects and applies right-to-left text direction for Arabic and Hebrew languages.

<zn-translations
  label="RTL Languages"
  languages='{"en":"English","ar":"Arabic","he":"Hebrew"}'
  values='{"en":"Hello World","ar":"مرحبا بالعالم","he":"שלום עולם"}'
></zn-translations>

Listening to Changes

The component emits zn-change events when translation values change.

Event Log:
<zn-translations
  id="trans-events"
  label="Translation Input"
  languages='{"en":"English","fr":"French"}'
></zn-translations>

<div style="margin-top: 1rem; padding: 1rem; background: var(--zn-color-neutral-50); border-radius: 4px;">
  <strong>Event Log:</strong>
  <div id="event-log-trans" style="margin-top: 0.5rem; font-family: monospace; font-size: 0.875rem;"></div>
</div>

<script type="module">
  const translations = document.getElementById('trans-events');
  const eventLog = document.getElementById('event-log-trans');

  translations.addEventListener('zn-change', (event) => {
    const timestamp = new Date().toLocaleTimeString();
    const value = JSON.parse(event.target.value);
    eventLog.innerHTML = `[${timestamp}] Translation changed: ${JSON.stringify(value, null, 2)}`;
  });
</script>

Form Integration

The component submits its translations as a JSON object under name. required marks the label, though validity is not enforced per language.


Submit Translations
<form class="translations-form">
  <zn-translations
    name="content"
    label="Article Content"
    required
    languages='{"en":"English","fr":"French","de":"German"}'
  ></zn-translations>
  <br />
  <zn-button type="submit" color="success">Submit Translations</zn-button>
</form>

<script type="module">
  const form = document.querySelector('.translations-form');

  await customElements.whenDefined('zn-translations');

  form.addEventListener('submit', (e) => {
    e.preventDefault();
    const formData = new FormData(form);
    const data = Object.fromEntries(formData);
    alert('Form submitted!\n\n' + JSON.stringify(data, null, 2));
  });
</script>

Programmatic Control

Access and modify translation values via JavaScript.

Set Sample Values Get Values Clear All
<zn-translations
  id="prog-trans"
  label="Programmatic Translations"
  languages='{"en":"English","fr":"French","es":"Spanish"}'
></zn-translations>

<div style="margin-top: 1rem;">
  <zn-button id="set-values-btn">Set Sample Values</zn-button>
  <zn-button id="get-values-btn" color="info">Get Values</zn-button>
  <zn-button id="clear-values-btn" color="secondary">Clear All</zn-button>
</div>

<script type="module">
  const trans = document.getElementById('prog-trans');

  document.getElementById('set-values-btn').addEventListener('click', () => {
    trans.values = {
      en: 'Sample English text',
      fr: 'Exemple de texte français',
      es: 'Texto de muestra en español'
    };
  });

  document.getElementById('get-values-btn').addEventListener('click', () => {
    alert('Current values:\n\n' + JSON.stringify(trans.values, null, 2));
  });

  document.getElementById('clear-values-btn').addEventListener('click', () => {
    trans.values = { en: '', fr: '', es: '' };
  });
</script>

Help Text

Use the help-text attribute to describe how the field should be filled in. It sits below the field and applies to every language, so it is the place to explain a convention the translator needs to follow. For help text containing HTML, use the help-text slot instead.


Shown on every page of the checkout.
<zn-translations
  label="Confirmation headline"
  help-text="Keep this under 60 characters so it does not wrap on mobile."></zn-translations>
<br />
<zn-translations label="Footer">
  <div slot="help-text">Shown on <strong>every</strong> page of the checkout.</div>
</zn-translations>

Slash Menu Quick Insertions

Copy that carries replacement strings — {{BRAND_NAME}} and the like — needs the same tokens in every language. Set slash-items and typing / offers them at the caret, in whichever language is being edited. This works on both the single-line default and input-type="textarea". The attribute takes the same shorthand and JSON that zn-textarea accepts, and slash-preset, slash-trigger and slash-heading are forwarded too.

<zn-translations
  label="Confirmation message"
  input-type="textarea"
  textarea-rows="4"
  languages='{"en": "EN", "fr": "FR", "de": "DE"}'
  values='{"en": "Look for /"}'
  slash-heading="Replacement strings"
  slash-items='[
    {"label": "Brand name", "value": "{{BRAND_NAME}}", "description": "The product / company name", "icon": "sell"},
    {"label": "Customer email", "value": "{{CUSTOMER_EMAIL}}", "description": "The customer&#39;s email address", "icon": "mail"},
    {"label": "Renewal price", "value": "{{RENEWAL_PRICE}}", "description": "The renewal price amount", "icon": "payments"}
  ]'></zn-translations>

The menu claims , , Enter, Tab and Escape while it is open, so choosing an item never submits the form the way Enter otherwise would.

Properties

Property Type Default Description
name string '' Form field name for submission
value string '{"en":""}' JSON string of translations
label string '' Label displayed above the component
help-text string '' Text shown below the field, describing how to fill it in
disabled boolean false Disables editing of all translations
required boolean false Makes the field required for form validation
flush boolean false Removes padding for compact layout
languages Record<string, string> {en: "EN"} Object mapping language codes to display names
values Record<string, string> {} Object mapping language codes to translation text
grouped boolean false Hides the language select; a parent zn-translation-group drives it
input-type 'text' | 'number' | 'textarea' 'text' The control each translation is edited through
textarea-rows number Rows of the textarea, when input-type is textarea
inline-edit boolean false Edits through zn-inline-edit instead of a plain input or textarea
slash-items SlashMenuItem[] [] Quick insertions offered by the slash menu
slash-preset string '' Registered item sets to offer, comma separated
slash-trigger string '/' The characters that open the slash menu
slash-heading string 'Insert' Heading shown above the slash menu’s items

Events

Event Description Event Detail
zn-change Emitted when any translation value changes {value: string}
zn-input Emitted when translation input changes None

Slots

Slot Description
label Alternative to the label attribute for rich HTML content
help-text Alternative to the help-text attribute for rich HTML content

Methods

Method Description
checkValidity() Checks form validity
reportValidity() Checks validity and shows message
setCustomValidity(message) Sets custom validation message
getForm() Returns the parent form element

CSS Parts

Part Description
form-control The component’s base wrapper
form-control-label The label’s wrapper
form-control-input The wrapper around the field being edited
language-select The select that chooses the language being edited

The component uses zn-select for the language and zn-input, zn-textarea or zn-inline-edit for the field, each of which exposes its own CSS parts for advanced styling.

Accessibility

  • The component automatically detects RTL languages (Arabic, Hebrew) and applies proper text direction
  • The language select is a standard combobox: it opens on Enter or Space and moves through the languages with the arrow keys
  • Enter submits the form from a single-line field, and inserts a newline in a textarea

Importing

If you’re using the autoloader or the traditional loader, you can ignore this section. Otherwise, feel free to use any of the following snippets to cherry pick this component.

To import this component from the CDN using a script tag:

<script type="module" src="https://cdn.jsdelivr.net/npm/@kubex/zinc@1.1.116/dist/components/translations/translations.js"></script>

To import this component from the CDN using a JavaScript import:

import 'https://cdn.jsdelivr.net/npm/@kubex/zinc@1.1.116/dist/components/translations/translations.js';

To import this component using a bundler:

import '@kubex/zinc/dist/components/translations/translations.js';

Slots

Name Description
label The field’s label. Alternatively, use the label attribute.
help-text Text describing how to fill the field in, shown below it and shared by every language. Alternatively, use the help-text attribute.

Learn more about using slots.

Properties

Name Description Reflects Type Default
name The name submitted with the form. string ''
value The translations as a JSON object keyed by language code. The mirror of values in attribute form. string '{"en":""}'
label The label shown above the field. If you need HTML, use the label slot instead. string ''
helpText
help-text
Text shown below the field, describing how to fill it in. Applies to every language. If you need HTML, use the help-text slot instead. string ''
disabled Disables editing in every language. boolean false
required Marks the label required. Validity is not enforced per language. boolean false
flush Removes the component’s own padding. boolean false
inputType
input-type
The control each translation is edited through. 'text' | 'number' | 'textarea' 'text'
textareaRows
textarea-rows
Rows of the textarea, when input-type is textarea. number | undefined -
inlineEdit
inline-edit
Edits the translation through a zn-inline-edit — the value reads as text until it is clicked — rather than a plain input or textarea. boolean false
slashItems
slash-items
Quick insertions offered by the slash menu on text and textarea inputs. Accepts a JSON array of items, or the shorthand Brand name={{BRAND_NAME}}, Support email={{SUPPORT_EMAIL}}. Every language shares the list. SlashMenuItem[] []
slashPreset
slash-preset
Names of item sets registered with registerSlashMenuPreset, comma separated. string ''
slashTrigger
slash-trigger
The characters that open the slash menu. string '/'
slashHeading
slash-heading
The name the slash menu’s list is announced by. string 'Insert'
slashHideKeys
slash-hide-keys
Hides the insertion keys normally shown against the slash menu’s items. boolean false
slashRecentKey
slash-recent-key
Lists the slash menu items most recently chosen here above the rest, remembered under this key. string ''
slashItemsProvider Resolves additional slash menu items each time the menu opens. JavaScript only. (query: string) => SlashMenuItem[] | Promise | undefined -
grouped Hides this component’s own language select and defers the choice to a parent zn-translation-group. The group sets this on its children itself. boolean false
languages The languages on offer, as language code to display name — {"en": "English", "fr": "French"}. Writing the code as the name ({"en": "EN"}) is also accepted. en is the language every other one falls back to. Record { 'en': 'EN' }
values The translations as an object keyed by language code. The mirror of value in property form. Record {}
defaultValue The serialized translations a form reset restores. Taken from the value attribute where there is one. string '{"en":""}'
updateComplete A read-only promise that resolves when the component has finished updating.

Learn more about attributes and properties.

Events

Name React Event Description Event Detail
zn-change Emitted when a translation’s value changes. -
zn-input Emitted when a translation receives input. -

Learn more about events.

Methods

Name Description Arguments
setActiveLanguage() Sets the active language externally. Used by zn-translation-group. Browsing to a language does not create a key for it — an untouched language stays absent from values so it is not submitted as an empty translation. language: string
getActiveLanguage() Returns the currently active language. -
addLanguageKey() Adds a language key to this component’s values if not already present. Used by zn-translation-group. languageCode: string
getValueLanguages() Returns all language codes that have values. -
hasTranslation() Whether the language carries a translation of its own, rather than falling back to English. language: string

Learn more about methods.

Parts

Name Description
form-control The form control that wraps the label, the language select, the field and the help text.
form-control-label The label’s wrapper.
form-control-input The wrapper around the field being edited.
form-control-help-text The help text’s wrapper.
language-select The select that chooses the language being edited.

Learn more about customizing CSS parts.

Dependencies

This component automatically imports the following dependencies.

  • <zn-chip>
  • <zn-example>
  • <zn-icon>
  • <zn-inline-edit>
  • <zn-input>
  • <zn-opt-group>
  • <zn-option>
  • <zn-popup>
  • <zn-select>
  • <zn-slash-item>
  • <zn-slash-menu>
  • <zn-tag>
  • <zn-textarea>
  • <zn-tooltip>