Download

How to translate your Publii theme to another language

It's easy enough to make a website in your native language with Publii; just create the content! But if you do, you'll quickly notice that there's a little problem: the additional bits of text that come with the theme, such as the "Published On" text you see at the top of a post or the button labels on your social media buttons, don't show up in the content editor or in the general options of Publii. This makes them a bit of a liability in a non-English site, since you'll always have a few stray bits of English messing up your aesthetics.

To solve this, Publii offers two ways to localize theme text. The easiest option is to use the Language File Editor Plugin, which allows you to edit theme language files directly from the Publii interface. The plugin creates a separate override file for your translations, so theme updates do not overwrite them. This lets you translate the theme without editing JSON files manually.

Download Language File Editor

Alternatively, translations can also be done manually by editing the theme's language files. The sections below provide a detailed guide on how to locate, override, and edit these files step-by-step. These methods apply to text provided by the theme; text added by plugins may have separate translation settings.

The Publii theme language file

The theme language file is named themeName.lang.json and is stored in the theme's folder. For the version installed on your website, look in <Sites location>/<site-folder>/input/themes/<theme-name>. You can check your sites location under App settings → Files location → Sites location; if the field is blank, Publii uses the default Documents/Publii/sites folder.

For example, if your website uses the Portfolio theme, open its input/themes/portfolio folder, where you'll find portfolio.lang.json. Use the copy installed on your website, as the version in the app's theme library may be different.

Portfolio theme folder with the portfolio.lang.json language file highlighted
The portfolio.lang.json file contains the Portfolio theme's default text.

Now, to translate the theme's text we technically could simply open the language file and edit it directly, but there's a problem; when the theme is updated the language file will be overwritten, and all our changes will be lost. Instead, we need a more permanent solution, which Publii already provides.

Instead of editing the file directly, we can create a copy that's unique to our website, which Publii can use to override the default language file. Let's go through it step-by-step.

Translating a Publii theme

  1. First, locate the language file for the theme you wish to translate. This will be in <Sites location>/<site-folder>/input/themes/<theme-name>. The filename will be themeName.lang.json, for example portfolio.lang.json. Here, <site-folder> means the website's folder on your computer; its name may differ from the website name displayed in Publii.

  2. Create a copy of the language file, leaving the original untouched where it is. Place the copy in <Sites location>/<site-folder>/input/languages, keeping exactly the same filename. If your input folder doesn't have a languages folder, create it manually and put the language file inside.

  3. Open the copy of the language file with your text editor of choice; even Notepad will work! Inside, you will see groups of translation entries. A text entry has the format "placeholderText": "translatedText". Text to the left of the colon is the key used by the theme and should remain unchanged. The text to the right is what will appear on the website. Here is an extract from the Portfolio theme's language file; the entries in your own theme may differ:

    {
        "partials": {
            "menu": {
                "label": "Menu"
            },
            "pagination": {
                "prev": "Previous",
                "next": "Next"
            }
        },
        "slider": {
            "button": "View project",
            "slide": "Slide %s"
        },
        "post": {
            "publishedBy": "By",
            "publishedOn": "Published on",
            "previousPost": "Previous Post",
            "nextPost": "Next Post"
        },
        "common": {
            "readmore": "View more"
        }
    }
    
  4. Translate each text value to the right of the colon. Don't modify the group names, keys or their nesting, as the theme uses these to find the correct translation. Keep any %s placeholders in your translated text, with the same number of placeholders as the original:

    {
        "partials": {
            "menu": {
                "label": "Your menu label here"
            },
            "pagination": {
                "prev": "Your previous button text here",
                "next": "Your next button text here"
            }
        },
        "slider": {
            "button": "Your slide button text here",
            "slide": "Your slide text here %s"
        },
        "post": {
            "publishedBy": "Your published by text here",
            "publishedOn": "Your publication date text here",
            "previousPost": "Your previous post button text here",
            "nextPost": "Your next post button text here"
        },
        "common": {
            "readmore": "Your read more button text here"
        }
    }
    
  5. With the text replaced with your own translation or interpretation, save the changes to the file. Keep the file valid JSON: use double quotes around keys and text values, and don't leave a comma after the last entry in an object. Now, when Publii generates your website, it will use your translations in place of the corresponding default text. Preview the site to check the result, then sync it when you're ready to publish.

For advanced users

There are two things to note for more advanced users. It is not necessary to include all of the code from the original language file in the override file. Instead, you can include only the string that you wish to change, keeping its original nesting. So if we only wanted to change the button label for the homepage slideshow in the Portfolio theme, we could create a language file with the following code inside:

{
    "slider": {
        "button": "Explore this project"
    }
}

This will override only the button text, leaving the rest untouched. Secondly, it's important to note the purpose of the %s text that can be seen in some translation strings, such as "Slide %s". Each %s is replaced with a value supplied by the theme, such as a slide number or an author name. Keep these placeholders in your translation; removing one or adding an extra one can cause a translation error.

More about that can be found below, in the Variable %s section.

How the .json language file works

So you've figured out how to make translations, but would like to know a bit more about how it works? Read on! In a standard website theme, the incidental text is hard-coded in, hidden away in the theme files, making it hard to get to. Of course, if you have a small amount of working knowledge of theming or code, then it's extremely easy to change it directly in the files. However, this isn't a viable solution most of the time; the average person isn't going to have much knowledge about coding, because it's not essential; this is why apps like Publii exist, after all! Secondly, whenever the theme files are updated, the changes will be overwritten and the text returned to the default.

So clearly a simpler, more user-friendly method of translating themes is required. In Publii's case, instead of hard-coding text into the themes, we instead utilize a language .json file, which acts a bit like a codebook of sorts. Basically, instead of putting text in the theme code, we'll put a piece of placeholder text; and in the language file, we'll define what each bit of placeholder text should be replaced with. Then, when Publii creates the files for the website, it will look for all the placeholder text, and replace them with their respective translations from the language file. Think of it as like reading a piece of algebra; a formula like "x + y = z" doesn't mean anything on its own, but if you define both "x" and "y", then the formula can be calculated. In a Publii theme, the "x" and "y" would be the placeholder text, which is then defined in the language file.

The language file structure

The best way to understand the language file is to get a look at its contents; despite the .json extension you can view it with pretty much any text editor, even Notepad! Let's look again at an extract from portfolio.lang.json, found in the website's input/themes/portfolio folder:

{
    "partials": {
        "menu": {
            "label": "Menu"
        },
        "pagination": {
            "prev": "Previous",
            "next": "Next"
        }
    },
    "slider": {
        "button": "View project",
        "slide": "Slide %s"
    },
    "post": {
        "publishedBy": "By",
        "publishedOn": "Published on",
        "previousPost": "Previous Post",
        "nextPost": "Next Post"
    },
    "common": {
        "readmore": "View more"
    }
}

As we can see in the above code, there are multiple groups of text separated by braces. A group is used to organize translations so that they're easy to find, and each group can have subgroups if necessary. In this example, partials contains the menu and pagination groups. A group starts with a name in quotation marks followed by a colon and an opening brace, such as "partials": {. These names and their nesting form part of the translation path used by the theme, so keep them unchanged in your override file.

The second type of content is the placeholder with translations; this is the real meat of the file. Unlike the categories, the references and translations will have two separate words in quote marks, to the left and right of the colon, like this: "placeholderText": "translationText". The text to the left of the colon (in this case, "placeholderText"), is the placeholder that will be entered into the theme code for Publii to replace when it creates the website. The text to the right of the colon ("translationText"), is the text that Publii will use to replace the placeholder text in the complete website.

Overriding the language file

Because the core files of the theme will be replaced with every update, Publii supports overrides. By creating a file with the same name as the theme's language file, but placing it in <Sites location>/<site-folder>/input/languages, you can add your own translations as described earlier in this article. When Publii creates the pages for your site, it looks for each requested translation in the override file first. If it is not available there, Publii uses the theme's default text. This lets you modify text without changing the theme's original files or losing your translations when the theme is updated.

After a theme update, check whether it introduces any new phrases that also need translating.

Variable %s

The %s that you sometimes see in a translation is a placeholder for a value supplied by the theme. Let's say that a theme has a bit of homepage text that says "Hello from the folks at websiteName", where websiteName is the name of the website. Each user that installs this theme will have a different website, so the theme can't hard-code a particular website name. Instead, it can use %s in the language file and pass @website.name to the translate helper. When Publii generates the site, the helper replaces %s with that website's name.

For example, in a theme that supports a tags.hbs template, we can replace %s with the number of tags. We will use tagsNumber for this; see the tags page documentation.

Language file:

{
    "tags": {
        "pageTitle": "Tags",
        "description": "Collection of all %s tags"
    }
}

In the tags.hbs file, use:

{{ translate "tags.description" tagsNumber }}

If the collection contains five tags, the result will be: "Collection of all 5 tags".

What are you waiting for?

Start building your site today.

  1. 1 Download Publii
  2. 2 Write your content
  3. 3 Publish your site
Create website