Languages: English Russian

Localization

i18n plugin for Luasmith provides tools to create multi-language websites. It uses Lettext, a Gettext implementation for Lua, allowing you to translate strings in your website templates utilizing a commonly used PO file format. The plugin automatically extracts strings and generates PO(T) files when building the website, so you don't have to have standard Gettext utilities (such as xgettext and msgmerge) being installed — everything is handled by Lettext and the plugin to simplify creation of multi-language websites.

The plugin is unfinished. While the core things are complete, there are still some important missing parts. Breaking changes are expected.

Content structure

You can use either lang field in front-matter or add a filename suffix to set the language of a page. A suffix is useful when you want some pages to be translations to each other, and the plugin will be aware of that, so you will be able to create a language switcher (like you can see one on the top of this page).

Assuming we have this content directory structure:

content/
 | index.md
 | index.ru.md
 | some_page.md

With some_page.md having lang = ru, this structure will be produced on output:

out/
 | index.html
 | ru/
    | index.html
    | some_page.md

Changing the links in the content of pages is done by the plugin, so you should write relative links' paths as they are in your content folder and there's no need to be bothered of the fact that the path to root will change.

Pipeline

There are just 2 things that you need to call in your pipeline for your content to be localized.

  1. i18n.localize(defaultLang, potAsDefault)

    This node walks over all items, changing their paths and relative links in the content as needed; it will also set required plugin-specific item fields.

    defaultLang is the language code for the default language of your website. Pages without lang field set and with no language code in file suffix are assumed to be pages in the default language. If defaultLang is nil, it will be set to en.

    potAsDefault defines whether the generated messages.pot file should be used as a fallback for strings translations for the default language. If the default language has multiple plural forms, it may be insufficient to use only msgid and msgid_plural to provide proper strings; if potAsDefault is true, you can add msgstr in the POT file to workaround that and the plugin will read proper strings, but that may not feel right to write "translations" into the POT file (which is the PO Template file), in such case you may want to set potAsDefault to false and then a separate PO file for your default language will be generated, allowing you to keep the POT file clean. If potAsDefault is nil, it will be set to true.

    If you use i18n plugin together with some other plugins that modify items' paths (such as anyslug or prettyurls) then i18n.localize must be called before other plugins' nodes to avoid losing filename suffixes with language codes.

  2. i18n.writeTranslations()

    This node writes all translation files into po directory. A PO file will be generated for each language that the plugin will encounter, so that you don't need to edit LINGUAS and/or create PO files yourself. This node should be called after applying all your template and doing other stuff that calls translation functions so that all strings will be collected.

There's also i18n.setLang(path, lang) currently available as a workaround for missing functionality to set the language and add some extra stuff to pipeline-generated pages (i.e. not generated from content files). This node will most likely be removed in the future.

Usage in templates

Most of the functionality of the plugin for templates can be inspected in the code of the language switcher on this page:

<% if nlangs > 1 then -%>
<div><%= _'Languages' .. ':' -%>
<%  for l, p in iterLangs() do
    if l == lang then -%>
    <b><%= getLangName(l) %></b>
    <% else -%>
    <a href="<%= p %>"><%= getLangName(l) %></a>
    <% end -%>
<%  end -%>
</div>
<% end -%>

nlangs is the count of languages the page is available in. This page in pacticular has nlangs being 2. The field is set automatically, don't overwrite it yourself.

_'Languages' is a translatable string. If you have ever written a code using Gettext, then you may be familiar with _(...), _p(...), _n(...) and _np(...) — these are translation function with slightly different options, but the main thing is the same: a string will be replaced by its translation from a messages catalog for the current language (or the original string is returned if there's no translation). See Lettext demo for detailed usage examples of these functions.

If you will look at messages.pot file in the source code of this website, an entry with the string is there:

msgid "Languages"
msgstr ""

iterLangs() iterates over all languages for the page, returning a language code and a path to the page in another language. The iterator will go over the current page itself, this can be detected by comparing returned language code with the language code of the current page (lang).

getLangName(lang) returns the name of the language for the provided code. Currently it returns the name in English, but this will change in the future. So, now it returns "English" for en and "Russian" for ru no matter what the current page's language is.

Now, one more thing that you can use in templates:

getLangRoot() returns a path to the language root directory for the current page.

Planned features