Statac

Write

Dates and languages

Write dates year first, choose how the pages show them, and set the language, or languages, a site is written in.

Write a date

Written Statac
2026-10-04 Reads the day.
2026-10-04 09:30 Reads the day and the time, in the site’s time zone.
2026-10-04T09:30 Reads the same: a space or a T parts the day from the time.
2026-10-04 09:30:15 Reads the seconds after the minutes.
2026-10-04 09:30+01:00 Reads the offset from UTC, written Z, +01:00, +0100 or +01, after a space if you like.

A date in front matter or in statac.yaml is written year first.

You seldom need to type one out:

Where the date comes from What is written
A stamp, such as date: =today statac serve or statac stamp writes the day over it: 2026-10-06. A stamp never writes an offset.
A file named 2026-10-04-post-1.md Nothing: the page takes its date from its name. A date: line giving another day wins.
statac import Each old date year first, keeping no more than it held: a day alone stays a day.

Time zones

In statac.yaml:

timezone: Europe/London

A date with no offset is read in the site’s timezone, which also decides what today is, for a stamp and for a post waiting for its day. statac new writes the computer’s own zone.

Without a timezone, such dates are read as UTC, never in the computer’s zone.

How dates look

In statac.yaml:

date_format: Wed 31 Dec 2025

date_format shows how dates look, by example. Write one moment, Wednesday 31 December 2025 at 15:04, the way you want every date written:

date_format 2026-03-04 09:05 is shown as
31 December 2025 4 March 2026
Wed 31 Dec 2025 Wed 4 Mar 2026
December 31, 2025 March 4, 2026
31/12/2025 04/03/2026
2025-12-31 2026-03-04
Wednesday 31st December 2025 at 3.04pm Wednesday 4th March 2026 at 9.05am

Anything else, such as at or /, is written as it stands.

You write Statac writes
31 The day, 4
31st The day in the language’s words, 4th
12, Dec or December The month, 03, Mar or March
2025 or 25 The year, 2026 or 26
Wed or Wednesday The weekday
15:04 The time, 09:05
3.04pm or 3:04 PM The time, 9.05am or 9:05 AM
  • With the month in figures, the day and the month keep a leading zero, 04/03/2026, unless date_zeros: false in statac.yaml makes it 4/3/2026.
  • The site’s date_format needs the day, the month and the year in full.
  • A date with no time is shown without one, and without the words leading into the time: Wednesday 4th March 2026.
  • Write the month and the weekday in the site’s language: 31 décembre 2025 on a site in French.

Without date_format, a date is written as the day, the month in words and the year: 4 March 2026 in English. German, Spanish, Japanese and Korean have a usual form of their own.

<p>{{ page.date | date("December 2025") }}</p>

The date filter shows one date in a style of its own, written the same way. Here any piece may be left out, and the year may be short.

In statac.yaml:

date_short: 31 Dec 2025
<time datetime="{{ post.date | moment }}">{{ post.date | date(site.date_short) }}</time>

The filter’s example can be a value of your own in statac.yaml. date_short is no setting of Statac’s: statac new writes three such lines for its templates.

Languages

In statac.yaml:

language: fr

language names the site’s language by its code, such as en, en-GB or fr. Dates are written in its words and digits, the writing’s quotation marks become its own, and templates have it as page.language. A site that names none is in English, as en.

Statac has the words of eight languages:

Language Code
Arabic ar
English en
French fr
German de
Japanese ja
Korean ko
Persian fa
Spanish es

For the seven besides English, Statac has the months and weekdays, the words for morning and afternoon, the quotation marks, the direction and the digits, from the Unicode CLDR. Anything else comes from the site’s own file.

A code with a region, such as en-GB, uses its language’s words where Statac has none for the region. In any other language, dates are written in figures and quotes stay as typed, until you give Statac the words.

Words for another language

In languages/sw.yaml:

months: [Januari, Februari, Machi, Aprili, Mei, Juni,
  Julai, Agosti, Septemba, Oktoba, Novemba, Desemba]
weekdays: [Jumatatu, Jumanne, Jumatano, Alhamisi, Ijumaa, Jumamosi, Jumapili]

A file in languages/ named after a code gives a language’s words, for a language Statac doesn’t know or to change some of its own. With this one, a site in Swahili writes date_format: 31 Desemba 2025.

Every line is optional. A line the file gives replaces Statac’s, and a line it leaves out keeps Statac’s.

  • A line with nothing after its colon takes Statac’s line away: digits: alone in languages/fa.yaml keeps Persian dates in the digits 0 to 9.
  • A file for a region adds to its language: languages/fr-CA.yaml adds to Statac’s fr.
Line What it holds
months, months_short The months, January first, as a date writes them.
months_alone, months_short_alone The months with no day beside them, where the language writes them differently.
weekdays, weekdays_short The days of the week, Monday first.
days The days of the month as words, 1st to 31st, for a format written with 31st. Statac has them in English alone.
am_pm The words for morning and afternoon: [am, pm] in English.
digits The ten digits, zero first. Dates and a footnote’s number are written in them, and the digits filter writes any other number in them.
quotes The outer pair of quotation marks, then the inner pair: quotes: « » “ ”. Without it, quotes in the writing stay straight. See punctuation.
inside_quotes A space written inside the outer pair, such as inside_quotes: " " for a space a line can’t break at.
no_break_before, no_break_after Marks before which, or after which, a typed space becomes one a line can’t break at: no_break_before: "; : ! ?". None is added where none was typed.
direction rtl for a language written right to left: templates have it as page.direction, and a footnote’s arrow back to the text turns from ↩ to ↪.
back_to_the_text What a screen reader says for a footnote’s link back to the text. Statac writes it as the link’s aria-label, and hands it to a site’s own footnotes.html as label.
callouts The names of the five kinds of callout: note, tip, important, warning and caution, in that order. A site’s own snippets/markdown/callout.html has them as title.

Statac has back_to_the_text and callouts in English only. For any other language they come from the site’s own file, which statac new writes with both lines in English for you to translate.

On a site with no snippet for callouts, Statac’s own callout shows no name in any language.

The words your pages show

The site's own words are in English in `data/words.yaml`, under `fr`, and Statac's in `languages/fr.yaml`. Translate them there.

Every word a new site’s templates and snippets show readers, such as “Older posts” or a callout’s name, is in data/words.yaml, under each language’s code. statac new writes them in English for every language. Translate the lines under a language’s code, and its pages show them.

The folders’ names in the menu, such as “Notes”, are not among them: each is the title in the folder’s index.md.

For a language added to language later, copy the English list under the new code, then translate it.

The starter lists every word in the file. Templates shows how a template reads them, and starting a site how --update adds a word a newer template shows.

A site in several languages

In statac.yaml, the main language first:

language: [ar, en]
content/
  index.md
  post-1.md
  en/
    index.md
    post-1.md
    notes/
      post-2.md

A folder at the top of content/ named exactly as language writes a code holds that language’s pages: here every page under content/en/ is in English. Every page outside the language folders is in the main language, Arabic here.

  • A page can’t choose its language in its front matter: where it stands says.
  • The main language may have a folder of its own too, such as content/ar/. Pages outside every language folder are still in the main language, so a page at / can welcome readers in every language.

Given several languages, statac new makes a folder and a home page for each besides the main one: see Starting a site.

Lists and feeds in each language

Arabic, at the top English, in content/en/
Home page / /en/
post-1.md /post-1/ /en/post-1/
Tag Rust /tags/rust/ /en/tags/rust/
Feed /feed.xml /en/feed.xml

Each language has a top: its folder, or content/ for a main language with no folder. The top is the language’s own list, every post in the language, and site.posts on its pages. A page in one language is in no other language’s lists or feeds.

  • A top with no index.md gets a home page built with templates/home.html. Each folder directly inside a top has a page and a feed, as lists and feeds describe.
  • Tags and series are each language’s own: Rust on an English page and Rust on an Arabic page are two tags.
  • A post’s previous and next, a list’s later pages, related(page), a posts: line and each: site.posts stay within the page’s language. in("blog") names a folder beneath the language’s top.
  • A feed is built in its list’s language, so it needs a title for that language: title or en.title.
  • Where the main language has a folder, content/ itself is no language’s list, and has no feed unless its page asks for one. On its pages, site answers for the main language.

Addresses in each language

In statac.yaml:

pages.permalink: /{year}/{slug}/

An Arabic post at the top lands at /2026/post-1/, and an English one at /en/2026/post-1/. Each address pattern is read from its language’s top: permalink: on a page or handed down, tags.permalink, series.permalink, and an each: page’s pattern. So permalink: /about/ on content/en/about.md publishes it at /en/about/.

Addresses written out are read from the top of the site: links in the writing, redirect_from and redirect_to. An English post that was at /en/2025/post-1/ writes that whole in redirect_from.

Settings for one language

In statac.yaml:

language: [ar, en]
title: Site 1
en.title: Site 2
en.date_format: Dec 31, 2025

title and date_format can be written for one language: its code, a dot and the setting, on one line. The plain line covers every language without one of its own.

A date_format for one language is written in that language’s words. One for every language may be in any of the site’s languages, and each page writes its dates in its own: date_format: 31 December 2025 shows 2026-10-04 as 4 October 2026 on English pages and as 4 أكتوبر 2026 on Arabic ones. The date filter reads its examples the same way.

Translations

With Arabic at the top of content/ and English in content/en/:

content/
  about.md
  blog/
    post-1.md
  en/
    about.md
    blog/
      post-1.md
Two pages in different languages are translations where Such as
They stand at the same path below their languages’ tops content/about.md and content/en/about.md above, and the two blog/post-1.md
Only the ending differs about.md and about.html
One is a folder’s index.md where the other is a file post-1/index.md, a post with its pictures beside it, and post-1.md
Both have the same translation_key, any text you choose content/about.md and content/en/about-us.md, each with translation_key: about
They stand at one place below two folders whose own pages share a key content/ar/books/book-1.md and content/en/book-list/book-1.md, once books/index.md and book-list/index.md share one

A page with a key is linked by its key alone, and a page outside every language folder is linked only by a key. The pages Statac makes have translations too: each language’s home page, and a tag’s or a series’ page where the same name stands in the other language’s address.

A draft, or a post waiting for its day, is no page’s translation until it is published.

Each language in templates

A new site’s base.html already does everything below. For templates of your own:

Name What it gives
page.language The page’s language, by its code, for lang.
page.direction ltr or rtl, the way the page’s lines run, for dir.
page.translations The same page in the site’s other languages, in the order language lists them. Each has its url, title and language. Empty where there is none.
site.languages Each language’s code, the main one first. Asked by a code, that language’s home page: site.languages.en.url. A site that names no language has en alone.
site.language, site.title Those of the page being built.
site.posts, site.folders, site.tags, site.series, site.feed Those of the page’s language.
site.pages Every page, in every language. Choose one language’s by page.language.
<html lang="{{ page.language }}" dir="{{ page.direction }}">

For search engines, each page lists in its <head> every language it is in, itself among them, and names the main language’s page with x-default:

{% if page.translations and site.url is defined %}
{% set main = site.languages | first %}
<link rel="alternate" hreflang="{{ page.language }}" href="{{ page.url | absolute }}">
{% for other in page.translations %}
<link rel="alternate" hreflang="{{ other.language }}" href="{{ other.url | absolute }}">
{% endfor %}
{% for one in [page] + page.translations if one.language == main %}
<link rel="alternate" hreflang="x-default" href="{{ one.url | absolute }}">
{% endfor %}
{% endif %}

absolute needs the site’s url, so the links are written only where the site has one.

A switch between languages links each other language to the page’s translation in it, or else to that language’s home page:

<nav aria-label="Languages">
{% for code in site.languages if code != page.language %}
{% set same = page.translations | selectattr("language", "eq", code) | list %}
{% set there = same[0] if same else site.languages[code] %}
<a href="{{ there.url }}" hreflang="{{ code }}" lang="{{ code }}">{{ code }}</a>
{% endfor %}
</nav>

The sitemap can list translations too: sitemaps.

Where next?

  • Front matter: stamps, which write a date into a page for you
  • Settings: timezone, date_zeros and every other line of statac.yaml
  • The starter: every file statac new writes, and every word in data/words.yaml
  • Lists, tags and series: the lists each language keeps, and their order

Something unclear or wrong? Open an issue on GitHub.