Guides

Internationalization (i18n)

Meno supports multi-language websites out of the box. You define which locales your project supports, then provide translations per locale for any text content. At build time, each locale gets its own set of HTML pages with the correct language content and URL prefixes.


Setting Up Locales

  1. Open Settings in the sidebar (or edit project.config.json directly).

  2. Under Internationalization, add the locales your site supports.

  3. Set one locale as the default locale. This locale has no URL prefix -- its pages live at the root (e.g. /about). All other locales get a prefix (e.g. /pl/about).

  4. Save. A locale switcher appears in the editor toolbar, letting you preview content in each language.

Configuration in project.config.json

{
  "i18n": {
    "defaultLocale": "en",
    "locales": [
      {
        "code": "en",
        "name": "EN",
        "nativeName": "EN",
        "langTag": "en-US",
        "icon": "/icons/us.svg"
      },
      {
        "code": "pl",
        "name": "PL",
        "nativeName": "PL",
        "langTag": "pl-PL",
        "icon": "/icons/pl.svg"
      },
      {
        "code": "de",
        "name": "DE",
        "nativeName": "DE",
        "langTag": "de-DE",
        "icon": "/icons/de.svg"
      }
    ]
  }
}

Each locale object has these fields:

Field

Description

code

Short locale code used in URLs and data (e.g. "en", "pl")

name

Display name in the default language

nativeName

Display name in the locale's own language

langTag

BCP 47 language tag for the lang HTML attribute (e.g. "en-US")

icon

Optional path to a flag icon


Translating Content in the Editor

  1. Use the locale switcher in the toolbar to select a locale.

  2. Select any element on the canvas.

  3. In the Properties panel, text fields show per-locale inputs when i18n is configured. Type the translation for the currently selected locale.

  4. Switch to another locale and enter its translation.

  5. The canvas updates in real time to show content for the active locale.

The editor stores translations using the _i18n object format (described in the "Under the Hood" section below). You do not need to write this format manually -- the editor handles it for you.


URL Structure

Meno generates locale-prefixed URLs for all non-default locales:

Locale

URL

en (default)

/about

pl

/pl/about

de

/de/about

For CMS items, the same pattern applies. A blog post with slug my-post:

Locale

URL

en (default)

/blog/my-post

pl

/pl/blog/my-post

If the CMS item has an i18n slug field, the slug itself can differ per locale, allowing fully localized URLs like /pl/blog/moj-post.


Adding a Language Switcher

To let visitors switch languages on the live site, add a Locale List node.

  1. Select the element where you want the switcher (typically a nav bar).

  2. Open the Command Palette (Cmd+E / Ctrl+E) and choose Add Locale List.

  3. The node appears in the structure tree. Select it to configure its properties.

Locale List Properties

Property

Type

Description

displayType

string

How to show locale text: "code", "name", or "nativeName"

showFlag

boolean

Show the flag icon next to the label

showCurrent

boolean

Include the currently active locale in the list

showSeparator

boolean

Show a separator between locale links

Styling

The Locale List supports these style slots:

Slot

Applies to

style

The outer container

itemStyle

Each locale link

activeItemStyle

The link for the current locale

separatorStyle

The separator element

flagStyle

The flag icon

All style slots accept the same responsive style format used throughout Meno (with base, tablet, and mobile breakpoints).


CMS i18n Fields

CMS collections can have per-locale content using the i18n and i18n-text field types.

  1. When defining a collection schema, set a field's type to i18n (for single-line text) or i18n-text (for multi-line text).

  2. In the CMS field editor, an input appears for each configured locale. Fill in the translation for each language.

  3. In templates, use the same {{cms.fieldName}} expression. The correct locale value is resolved automatically based on the page's current locale.

Example Schema with i18n Fields

In the template page's meta.cms.fields:

{
  "title": {
    "type": "i18n",
    "required": true,
    "label": "Title"
  },
  "description": {
    "type": "i18n-text",
    "label": "Description"
  },
  "slug": {
    "type": "i18n",
    "required": true,
    "label": "URL Slug"
  },
  "category": {
    "type": "select",
    "options": ["tech", "design"],
    "label": "Category"
  }
}

The title, description, and slug fields store a value per locale. The category field is shared across all locales.


Under the Hood

The _i18n Object Format

Internationalized prop values use a special object format with the _i18n flag:

{
  "text": {
    "_i18n": true,
    "en": "Hello",
    "pl": "Czesc",
    "de": "Hallo"
  }
}

When the page is rendered for a given locale, the system resolves this object to the correct string. For the pl locale, {{text}} becomes "Czesc". If a translation is missing, it falls back to the default locale.

Locale List Node JSON

{
  "type": "locale-list",
  "displayType": "nativeName",
  "showFlag": true,
  "showCurrent": false,
  "showSeparator": true,
  "style": {
    "base": {
      "display": "flex",
      "gap": "8px",
      "alignItems": "center"
    }
  },
  "itemStyle": {
    "base": {
      "textDecoration": "none",
      "color": "#333",
      "fontSize": "14px"
    }
  },
  "activeItemStyle": {
    "base": {
      "fontWeight": "bold",
      "color": "#000"
    }
  },
  "flagStyle": {
    "base": {
      "width": "20px",
      "height": "14px"
    }
  }
}

Build Output

At build time, Meno generates a complete copy of every page for each locale:

dist/
  index.html              # en (default locale)
  about.html
  blog/
    my-post.html
  pl/
    index.html            # pl
    about.html
    blog/
      my-post.html        # or moj-post.html if slug is i18n
  de/
    index.html            # de
    about.html
    blog/
      my-post.html

The generated HTML includes the correct lang attribute on the <html> tag, hreflang link elements for SEO, and all text content resolved to the appropriate locale.

Page-Level i18n Props

Any component prop can be made locale-aware by using the _i18n object format in the page JSON:

{
  "type": "component",
  "component": "HeroBanner",
  "props": {
    "heading": {
      "_i18n": true,
      "en": "Welcome to our site",
      "pl": "Witamy na naszej stronie",
      "de": "Willkommen auf unserer Seite"
    },
    "buttonLabel": {
      "_i18n": true,
      "en": "Get Started",
      "pl": "Rozpocznij",
      "de": "Loslegen"
    },
    "maxWidth": 1200
  }
}

Non-i18n props (like maxWidth above) work the same in every locale.


Next Steps

  • CMS -- Set up collections with i18n fields

  • Lists -- Display localized content in lists

  • Filtering and Search -- Filter content on the client side

  • Deployment -- Build and deploy multi-language sites

Building the future of digital experiences, one website at a time

© 2026 Company. All rights reserved.