Zine

Multilingual Websites

Creating Multilingual Websites

To create a multilingual website, use multilingualWebsite in your build.zig, like in the following example.

const std = @import("std");
const zine = @import("zine");

pub fn build(b: *std.Build) !void {
    zine.multilingualWebsite(b, .{
        .host_url = "https://kristoff.it",
        .layouts_dir_path = "layouts",
        .assets_dir_path = "assets",
        .i18n_dir_path = "i18n",
        .localized_variants = &.{
            .{
                .locale_code = "en-US",
                .output_prefix_override = "",
                .title = "Loris Cro's Blog",
                .content_dir_path = "content/en-US",
            },

            .{
                .locale_code = "it-IT",
                .title = "Loris 🤌 Cro's 🤌 Blog",
                .content_dir_path = "content/it-IT",
            },
        },
    });
}

Localized variants

Each variant can define the following fields:

locale_code

A language-NATION string, e.g. en-US, en-UK, it-IT, ja-JP.

title

Site title for this variant.

content_dir_path

Content directory with localized versions of your content.

host_url_override (optional)

The default assumption in Zine is that all your localized variants will be deployed on the same host, with each localization made available under a locale_code prefix:

Some users might want instead to serve each localization from a different hostname:

Setting host_url_override for each localized variant will make Zine generate permalinks accordingly.

output_prefix_override (optional)

This field can be used to override the path prefix for a localized variant. When host_url_override is set to null, the default prefix for each localized variant is locale_code. When host_url_override is set to a non-null value, the default prefix is "" (empty string).

You can set output_prefix_override to any string to place a localized variant under an arbitrary prefix. Setting it to an empty string is a good way of creating a “default variant” of the website.

For example by setting ouptput_prefix_override to empty string in en_US this is the resulting site layout:

Here’s a table with more examples:

output prefix override host url override resulting url prefix output prefix
null null /en-US/ zig-out/en-US/
null “us.site.com” / zig-out/en-US/
“foo” null /foo/ zig-out/foo/
“foo” “us.site.com” /foo/ zig-out/foo/
“” null / zig-out/

The i18n Directory

When creating a multilingual website, the assumption is that the same layouts and site assets will be reused across all localized variants, while the content folder will vary for each.

NOTE

To have per-variant assets you can both create appropriate subdirectories in your site assets directory and also leverage page-local assets.

Varying the content folder will allow you to create different localizations of your content, but that alone is not enough to provide localizedd versions of your site.

The i18n directory must contain a Ziggy file for each of your localized variants that will then be made available in order to provide localizations for phrases present in your layouts.

Localized variants and their Ziggy file are matched using the locale_code field.

$ tree i18n

i18n
├── en-US.ziggy
└── it-IT.ziggy

Each file contains a Ziggy map that can then be accessed from your layouts as $i18n.

$ cat i18n/it-IT.ziggy

{
 "back2top": "Ritorna in cima",
 "hello": "Ciao {}!",
}

Normal Scripty builtin functions are perfect for basic access to translations in layouts.

error if phrase is missing

<a href="#top" :text="$i18n.get('back2top')"></a>

default value fallback

<a href="#top" :text="$i18n.getOr('back2top', 'Top')"></a>

render element only if the phrase is present

<div :if="$i18n.get?('back2top')">
  <a href="#top" :text="$if"></a>
</div>

format the phrase (fmt is a string function)

<p :text="$i18n.get('hello').fmt($page.author)"></p>

Discovering localizations

To discover other localized variants for the same page, you can use $page.locales().

Refer to the SuperHTML Scripty reference to see how to use the resulting value.

Consider the following directory structure:

content
├── en-US
│   ├── about.smd
│   ├── docs
│   │   └── index.smd
│   └── index.smd
└── it-IT
    ├── about.smd
    ├── pasta.smd
    ├── docs.smd
    └── index.smd

That said, it is possible to match any page with any other by setting translation_key in the Ziggy frontmatter of each page.

This last way of matching pages is meant to be used when URL paths are also localized, for example:

The following frontmatter key must be set in both “contact us” pages:

.translation_key = "contact page"

The translation key can be any string value, as long as it is unique per each localized variant.