---
title: "Localization · Leiho"
description: "Declare your languages once. Each field is translatable or shared, translations sit next to the original, and your editors, your AI and your agents translate in the same editor. No copy of every page per language."
url: https://leiho.dev/features/localization
lang: en
updated: 2026-11-04
---
Localization

# Every language, one entry.

Declare your languages once. Each field is translatable or shared, translations sit next to the original, and your editors, your AI and your agents translate in the same editor. No copy of every page per language.

- [Try it in your browser](https://leiho.dev/try)
- [Read the docs](https://leiho.dev/docs)

![The Leiho visual editor in French, with the language menu open](https://leiho.dev/captures/editor-languages.png)

### Field by field

Titles and texts get one value per language. Prices, images, dates and references stay shared, so a new photo shows in every language at once.

### No duplicate entries

One entry holds every language. Adding a language never doubles your pages, your menus or your relations.

### Translate in the editor

Switch language in the toolbar and edit on the translated page. Empty fields show the original as a hint.

### AI translation

Translate with AI fills what is missing with your brand context, keeps HTML and product names, and waits for your review.

### Agents over MCP

Claude, Codex or Cursor read the original, write the translation and list what is left, without ever replacing reviewed text.

### Always something to show

Anything not translated yet, down to one row of a list, falls back on the original. Each language has its state: missing, partial, outdated, complete.

## Declared in the schema

Languages live in leiho.schema.json with the rest of your content model. The first one is the default: its content does not move.

```json
{
  "leiho": "collections",
  "version": 1,
  "i18n": { "default": "en", "locales": ["en", "fr", "de"] },
  "collections": [
    { "id": "service", "path": "/services/{slug}", "fields": [
      { "name": "title", "type": "text" },
      { "name": "price", "type": "number", "localized": false }
    ] }
  ]
}
```

## One build per language

Load the export in each language. Translated items have /fr/ paths and the address of every language, ready for a language switcher and hreflang.

```build
import { loadLeihoContent, indexLeihoContent } from 'leiho/content';

const fr = indexLeihoContent(
  (await loadLeihoContent({ url: 'https://cms.example.com', locale: 'fr' })).data
);

const page = fr.byPath('/fr/services/audit');
page.translations; // { en: '/services/audit', fr: '/fr/services/audit' }
```

### Built for many languages

Translations are stored in one table, one row per entry and language, apart from the original. Ten languages are ten rows, not ten copies of your site to keep in sync.

### Agents fill the gaps

leiho/list-translations shows what is missing, leiho/get-translation gives the original by path, leiho/update-translation writes it. On a published entry an agent can only fill empty translations.

More features

- [**Visual editing**Click and type on the real page](https://leiho.dev/features/visual-editing)
- [**Collections**Your content model, with or without ACF](https://leiho.dev/features/collections)
- [**Content API**One request, typed, cached](https://leiho.dev/features/content-api)
- [**Publishing**Live, build hook, GitHub Actions, Coolify](https://leiho.dev/features/publishing)
- [**AI and agents**Brand voice and MCP for your agents](https://leiho.dev/features/ai)
- [**SEO and AI search**Structured data, llms.txt, Markdown](https://leiho.dev/features/ai-search)

## Edit the real site.

Free and open source. Try it on a real WordPress, in your browser.

- [Try it in your browser](https://leiho.dev/try)
- [View on GitHub](https://github.com/pixelersagency/leiho)
