Skip to content HtmlpressStatic site generator HtmlpressStatic site generator

Change theme

Keyboard shortcuts

Translations

Updated

A site can be published in several languages. The first language is the default and keeps its URLs; every other one is served under its own prefix, such as /es/, with its own navigation, search, llms.txt and UI strings. The header gets a language picker, and a page not translated yet stays in the navigation, marked with the language it is written in.

Configure the languages

htmlpress.yaml
languages:
  - code: en
    label: English
  - code: es
    label: Español
  - code: zh
    label: 简体中文

Each language accepts:

Field Default Purpose
code none, required The URL prefix and the file name suffix: lowercase letters, digits and -, starting with a letter.
label none, required The name shown in the language picker.
locale the code The tag for <html lang>, hreflang and dates, such as pt-BR.
dir rtl for Arabic, Hebrew, Persian, Urdu and a few more ltr or rtl, written to <html dir>.
flag the locale's region, else the language's usual country A two-letter country code for the picker's flag, such as br; one without a bundled flag shows none.
messages none UI strings replacing the built-in ones; see below.

Without languages the site is a single English one, and nothing below applies. A code listed twice, an unknown message key, or a section whose prefix sits under another language's prefix (/es/…) fails the build.

Translate a page

A translation is a file beside its original, named with the language's code before .html. It is served under the language's prefix and paired with the original by URL:

  • index.html — /
  • index.es.html — /es/
  • guides
    • install.html — /guides/install/
    • install.es.html — /es/guides/install/

A suffix that names no configured language stays part of the name, so vite.config.html is still an English page. To keep translations in a folder of their own, or to name a file freely, set the language in its head instead; a file already under the language's folder is not prefixed twice:

es/guias/instalar.html
<meta name="language" content="es" />
<meta name="path" content="/guides/install/" />
es/guias/instalar.md
---
language: es
path: /guides/install/
---

A translation pairs with its original only when both share a URL below the language prefix, so give a renamed file the same path as its original. A language the config does not list fails the build.

Translate the config

The site's title, description and banner, a link's title, and a section's title, siteTitle and siteDescription take one text for every language, or a map by language code. A language missing from the map gets the default language's text:

htmlpress.yaml
title:
  en: Acme Docs
  es: Documentación de Acme
sections:
  - title: { en: Guide, es: Guía, zh: 指南 }
    prefix: /
  - title: Blog
    type: blog
    prefix: /blog/

Every section and every link with a prefix is mirrored under each language's prefix: the Spanish blog lives at /es/blog/, with its own index, tag pages and RSS feed listing the Spanish posts, then the default ones not translated yet. A changelog section builds its pages in every language, keeping the release notes as written; those copies point their canonical URL at the default language's and stay out of the sitemap. A custom section whose url is a page of the site leads to that page's translation, when the open language has one.

Pages not translated yet

A language lists every default-language page it has no translation of, so its navigation keeps the same shape. Such an entry links to the original and carries the default language's code as a badge, with "Not translated yet" as its tooltip. The untranslated page is built once, in its own language; search and llms.txt list only a language's own pages.

The language picker links each language to this page's version in it, else to that language's home. A language without a home page of its own, index.es.html, gets a redirect from /es/ to its first page; so does the default language without an index.html. Hosts that read _redirects, such as Cloudflare and Netlify, and htmlpress start redirect on the server; others fall back to a redirect page.

UI strings

Htmlpress' own strings, such as "Contents", "Previous" and "Edit this page", and the dates, are bundled in English, German, Spanish, French, Japanese, Russian and Chinese, picked by the locale's language. Any of them can be replaced per language:

htmlpress.yaml
languages:
  - code: en
    label: English
    messages:
      page.edit: Edit on GitHub
  - code: pt
    label: Português
    locale: pt-BR
    messages:
      toc.title: Nesta página
      nav.previous: Anterior
      nav.next: Próximo

A language htmlpress does not bundle falls back to English for the strings it does not set. The keys are the ones in messages/en.yaml; {name} placeholders such as {date} are filled in. date.format and date.months shape every date shown to readers.

What a translated page gets

  • <html lang> and, for right-to-left languages, <html dir="rtl">.
  • With site set, an hreflang alternate for every language that has the page, plus x-default pointing at the default language's version, and an og:locale.
  • Its language's search index, _htmlpress/search.<code>.json, and a Markdown copy and llms.txt under the language's prefix.
  • The <htmlpress-language> picker, which a layout escape places like any other element; it is removed on a single-language site.

See also

Created with ❤ and Htmlpress

Actions

Edit on GitHubView as Markdown

Contents