Skip to content

Internationalization

The editor UI supports locale switching. All labels, tooltips, placeholders, and messages are driven by translation keys — no hardcoded strings.

Setting the locale

Pass the locale option to init():

ts
import { init } from '@templatical/editor';

const editor = await init({
  container: '#editor',
  locale: 'de',
});

Built-in locales

CodeLanguage
enEnglish (default)
deGerman

Locale resolution

The editor normalizes locale codes by stripping region suffixes:

InputResolved
'en'en
'en-US'en
'en-GB'en
'de-AT'de
'fr'en (unsupported, falls back to English)

If the resolved locale is not supported, the editor falls back to English silently.

Async loading

Locale files are loaded asynchronously using dynamic import(). Only the active locale is bundled into the client — the other locale files are not included in your build. This means switching locales at runtime requires re-initializing the editor:

ts
async function switchLocale(newLocale: string) {
  editor.unmount();
  editor = await init({
    container: '#editor',
    locale: newLocale,
  });
}

How translations work

Translations are nested objects organized by UI section:

ts
{
  blocks: {
    paragraph: 'Paragraph',
    image: 'Image',
    button: 'Button',
    // ...
  },
  toolbar: {
    duplicate: 'Duplicate',
    delete: 'Delete',
    // ...
  },
  blockSettings: {
    spacing: 'Spacing',
    padding: 'Padding',
    // ...
  },
  templateSettings: {
    layout: 'Layout',
    // ...
  },
}

Some strings support placeholder interpolation using {placeholder} syntax:

ts
{
  header: {
    templatesUsed: '{used}/{max} templates used',
  },
}

Contributing a new locale

To add a new language:

  1. Copy packages/editor/src/i18n/locales/en.ts to a new file (e.g., fr.ts)
  2. Translate all string values, keeping the same key structure
  3. Register the locale in packages/editor/src/i18n/index.ts
  4. Run bun run test to verify key parity — tests check that all locales have the same keys as English

The translation file structure must exactly match the English file. Every key present in en.ts must also be present in your new locale file.

Example structure for a new locale:

ts
// packages/editor/src/i18n/locales/fr.ts
export default {
  blocks: {
    paragraph: 'Paragraphe',
    image: 'Image',
    button: 'Bouton',
    section: 'Section',
    divider: 'Séparateur',
    spacer: 'Espacement',
    // ... all keys from en.ts
  },
  toolbar: {
    duplicate: 'Dupliquer',
    delete: 'Supprimer',
    // ...
  },
  // ... all sections from en.ts
};

Submit a pull request with your translation file. Contributions for any language are welcome.