---
meta:
  title: Translation Group
  description: A panel-styled container that provides a shared language select for multiple translation inputs.
layout: component
---

The Translation Group component wraps multiple `zn-translations` components in a panel-styled container with a shared
language select. The select sits at the top right of the header, opposite the caption. Closed, it carries how many
languages are done as a `1/5` chip; open, each language is marked translated, partial or falling back to English.
Choosing a language switches every child at once.

```html:preview
<zn-translation-group
  label="Product Content"
  languages='{"en":"English","fr":"French","de":"German"}'>
  <zn-translations
    label="Name"
    name="name"
    values='{"en":"Wireless Headphones","fr":"Écouteurs sans fil","de":"Kabellose Kopfhörer"}'
  ></zn-translations>
  <zn-translations
    label="Description"
    name="description"
    values='{"en":"Premium noise-cancelling headphones","fr":"Écouteurs antibruit premium","de":"Premium-Kopfhörer mit Geräuschunterdrückung"}'
  ></zn-translations>
</zn-translation-group>
```

## Examples

### Basic Usage

A translation group with two translation inputs sharing one language select.

```html:preview
<zn-translation-group languages='{"en":"English","fr":"French"}'>
  <zn-translations label="Title" name="title"></zn-translations>
  <zn-translations label="Subtitle" name="subtitle"></zn-translations>
</zn-translation-group>
```

### With Label

Use the `label` attribute to add a caption on the left of the header, opposite the language select. `language-label`
sets the select's accessible name — it is not shown, since the caption names the section on screen.

```html:preview
<zn-translation-group
  label="Page Translations"
  languages='{"en":"English","fr":"French","es":"Spanish"}'>
  <zn-translations label="Heading" name="heading"></zn-translations>
  <zn-translations label="Body" name="body"></zn-translations>
</zn-translation-group>
```

### Pre-filled Values

Set initial translations on each child. A language every child has a value for is marked `Translated`; one only some
children have is `Partial`; one no child has falls back to English. English itself is the source, so it is neither
counted nor marked as a translation.

```html:preview
<zn-translation-group
  label="Notification Templates"
  languages='{"en":"English","fr":"French","de":"German","es":"Spanish"}'>
  <zn-translations
    label="Subject"
    name="subject"
    values='{"en":"Welcome aboard!","fr":"Bienvenue !","de":"Willkommen!","es":"Bienvenido!"}'
  ></zn-translations>
  <zn-translations
    label="Preview Text"
    name="preview"
    values='{"en":"Get started with your account","fr":"Commencez avec votre compte","de":"Starten Sie mit Ihrem Konto","es":"Comience con su cuenta"}'
  ></zn-translations>
</zn-translation-group>
```

### Many Languages

Every configured language is offered whether or not it has been translated yet, so there is no separate step to add
one — pick it and start typing. The chip on the closed select tracks how many are done.

```html:preview
<zn-translation-group
  label="Release Notes"
  languages='{"en":"English","ar":"Arabic","de":"German","es":"Spanish","fr":"French","it":"Italian","ja":"Japanese","ko":"Korean","pt":"Portuguese","ru":"Russian","tr":"Turkish","zh-hans":"Simplified Chinese"}'>
  <zn-translations
    label="Headline"
    name="headline"
    values='{"en":"Now shipping","ar":"متاح الآن","de":"Jetzt verfügbar","es":"Ya disponible","fr":"Disponible dès maintenant","it":"Disponibile ora","ja":"発売開始","ko":"출시됨","pt":"Disponível agora","ru":"Уже в продаже","tr":"Şimdi mevcut","zh-hans":"现已发布"}'
  ></zn-translations>
  <zn-translations
    label="Summary"
    name="summary"
    values='{"en":"Tap through the release highlights.","ar":"تصفح أبرز ميزات الإصدار.","de":"Highlights der Version ansehen.","es":"Consulta lo más destacado.","fr":"Découvrez les nouveautés.","it":"Scopri le novità.","ja":"リリースのハイライトをご覧ください。","ko":"업데이트 주요 내용 보기.","pt":"Veja os destaques.","ru":"Ознакомьтесь с обновлениями.","tr":"Sürüm önemli noktaları.","zh-hans":"浏览版本亮点。"}'
  ></zn-translations>
</zn-translation-group>
```

### Custom Accessible Name

`language-label` is read out by a screen reader in place of a visible label.

```html:preview
<zn-translation-group
  language-label="Language"
  languages='{"en":"English","fr":"French","de":"German"}'>
  <zn-translations label="Heading" name="heading" values='{"en":"Now shipping","de":"Jetzt verfügbar"}'></zn-translations>
  <zn-translations label="Body" name="body" values='{"en":"Tap through the highlights."}'></zn-translations>
</zn-translation-group>
```

### Inline (No Panel)

Nested inside another panel, the group's own border and padding indent its fields out of line with everything around
them. `inline` drops the chrome so the group reads as a section of the form instead.

```html:preview
<zn-panel caption="Product Details" icon="inventory_2">
  <div style="display: flex; flex-direction: column; gap: 1rem;">
    <zn-input label="Product SKU" value="PROD-12345" readonly></zn-input>

    <zn-translation-group
      inline
      label="Translatable Content"
      languages='{"en":"English","fr":"French","de":"German"}'>
      <zn-translations
        name="name"
        label="Product Name"
        values='{"en":"Premium Wireless Headphones","fr":"Écouteurs sans fil premium","de":"Premium kabellose Kopfhörer"}'
      ></zn-translations>
      <zn-translations
        name="short-description"
        label="Short Description"
        values='{"en":"High-quality wireless audio","fr":"Audio sans fil haute qualité","de":"Hochwertiges kabelloses Audio"}'
      ></zn-translations>
    </zn-translation-group>

    <zn-input label="Price" type="currency" value="299.99"></zn-input>
  </div>
</zn-panel>
```

### Actions

Buttons for the bottom of the group go in the `actions` slot. They sit on the white body rather than the grey
`footer`, and follow zinc's form action rows in sitting on the right. `align="start"` moves one to the left; any
number can sit on either side. Write them in the order they should be read — the sides are set by CSS ordering, so
markup order is what a keyboard follows.

```html:preview
<zn-translation-group
  label="Product Content"
  languages='{"en":"English","fr":"French","de":"German"}'>
  <zn-translations label="Name" name="name" values='{"en":"Wireless Headphones","de":"Kabellose Kopfhörer"}'></zn-translations>
  <zn-translations label="Description" name="description" values='{"en":"Premium noise-cancelling headphones"}'></zn-translations>

  <zn-button slot="actions" align="start" color="transparent" icon="translate">Auto-translate</zn-button>
  <zn-button slot="actions" color="secondary">Cancel</zn-button>
  <zn-button slot="actions" color="success">Save</zn-button>
</zn-translation-group>
```

### Flush Layout

Remove body padding for a more compact appearance using the `flush` attribute.

```html:preview
<zn-translation-group
  flush
  label="Compact Translations"
  languages='{"en":"English","fr":"French"}'>
  <zn-translations label="Label" name="label"></zn-translations>
  <zn-translations label="Placeholder" name="placeholder"></zn-translations>
</zn-translation-group>
```

### Listening to Language Changes

The group emits a `zn-language-change` event when the active language changes.

```html:preview
<zn-translation-group
  id="group-events"
  label="Event Demo"
  languages='{"en":"English","fr":"French","de":"German"}'>
  <zn-translations label="Title" name="title"></zn-translations>
  <zn-translations label="Description" name="description"></zn-translations>
</zn-translation-group>

<div style="margin-top: 1rem; padding: 1rem; background: var(--zn-color-neutral-50); border-radius: 4px;">
  <strong>Active Language:</strong>
  <span id="active-lang" style="font-family: monospace;">en</span>
</div>

<script type="module">
  const group = document.getElementById('group-events');
  const display = document.getElementById('active-lang');

  group.addEventListener('zn-language-change', (event) => {
    display.textContent = event.detail.language;
  });
</script>
```

## Properties

| Property         | Type                     | Default            | Description                                       |
|------------------|--------------------------|--------------------|---------------------------------------------------|
| `label`          | `string`                 | `''`               | Caption displayed in the panel header             |
| `language-label` | `string`                 | `'Edit Languages'` | The select's accessible name; not shown on screen |
| `inline`         | `boolean`                | `false`            | Drops the panel border, background and padding    |
| `languages`      | `Record<string, string>` | `{en: "EN"}`       | Object mapping language codes to display names    |
| `flush`          | `boolean`                | `false`            | Removes body padding for compact layout           |

## Events

| Event                | Description                              | Event Detail           |
|----------------------|------------------------------------------|------------------------|
| `zn-language-change` | Emitted when the active language changes | `{ language: string }` |

## Slots

| Slot      | Description                                                |
|-----------|------------------------------------------------------------|
| (default) | Place `<zn-translations>` elements here                    |
| `label`   | Alternative to the `label` attribute for rich HTML content |
| `actions` | Buttons for the bottom of the body; `align="start"` on a child moves it to the left |
| `footer`  | Content displayed in the grey panel footer                |

The header carries the caption and the language select alone; nothing else is slotted into it.

## CSS Parts

| Part              | Description                                                     |
|-------------------|-----------------------------------------------------------------|
| `base`            | The outer panel wrapper                                         |
| `header`          | The header area containing the caption and the language select  |
| `language-field`  | The container holding the language select                       |
| `language-select` | The select itself                                               |
| `actions`         | The row of buttons at the bottom of the body                    |
| `translations`    | The body container wrapping the slotted children                |
