Making a multilingual website with collections

Because it involved quite a bit of trial and error, I’m sharing this blog post here: Making a multilingual website with Jekyll collections. Perhaps it’s of help when you’re also adding translations to your site :slight_smile:

6 Likes

Thank you. You have inspired me! I have improved your solution (IMO). The following code respects collections and sets a language parameter based on a folder within the collection:

file structure:

_posts
  en
    2020-01-01-test-post.md
    2020-01-02-second-post.md
  nl
    2020-01-01-testbericht.md
    2020-01-02-tweede-bericht.md
_customcollection
  en
    first-post.md
  nl
    eerste-bericht.md

_config:

defaults:
- scope:
    path: '_posts/en'
  values:
    permalink: 'news/:title'
    language: en
- scope:
    path: '_posts/nl'
  values:
    permalink: 'nieuws/:title'
    language: nl
- scope:
    path: '_customcollection/en'
  values:
    permalink: 'custom/:title'
    language: en
- scope:
    path: '_customcollection/nl'
  values:
    permalink: 'maatwerk/:title'
    language: nl

layout file:

{% assign siteposts = site.posts | where: 'page',page.language %}
{% for item in siteposts limit:20 %}
  ...
{% endfor %}

I love it! Be careful though: site.posts is a collection too. That means that if you add collections, you will have to add them to the siteposts variable. For instance like this: {{ site.pages | concat: site.documents }}.

Can you create a directory with all content (pages, posts) for each language with your approach?

Thanks! I have updated my post with a custom collection and wrote an article about my approach here: https://www.usecue.com/blog/multilingual-jekyll-websites/

Thanks, it’s possible to get a reference to github to see the files?

Here you go: https://github.com/jhvanderschee/usecuewebsite

I can see the post is old so, so maybe things change but as someone new to Jekyll but an old timer programmer can someone confirm which layout file should this be in?

I tried it on default.html on a vanilla jekyll site running on my local and I just see the raw liquid file, i wondered if there should be multple default layouts ?
I am definitely missing something, is there a sample github repo where I can see a working example of this?

Thanks

The liquid tags can be in any of your layout files; just add them where you need them. If you want, you can nest layouts or use {% include ... %} to include a liquid file with code you use in multiple layouts.

thanks @Koos much appreciated
What I did is create two separate home pages, problem seems to be about getting the page.language,

I have a workaround to filter the language using the post language and that works fine for what I need

When I output page.language is just an empty string

page.language should be defined by adding language: en to the frontmatter of the page itself (not the layout). Where ‘en’ is the code for the language.

If you wan to define the language on the layout (perhaps each language deserves their own design), you can define the language in the layout’s frontmatter too. From the layout that’s called by the that same layout, or in the layout itself, you can access that value via layout.language.

I think in practice you’re usually better off not defining languages on templates but doing that directly on pages and collections. That way you can use [templates in all languages.

ah! that makes total sense! I was fixated on the language being derived from the browser information or similar

I think in practice you’re usually better off not defining languages on templates but doing that directly on pages and collections.

Great advice
Thanks @Koos

Thanks, I’ll check this out. I’m making a multilingual site and after trying the available plugins unsuccessfully, and just rolling it myself.

My site structure is, eg,

/en/ruby/_posts/2024-12-12-how-to-slurp-a-file.md

With a strictly enforced structure like that, I can easily make filters like:

module Jekyll
  module AssetFilter

    # Provide access to the `_config.yml` hash.
    # https://jekyllrb.com/docs/plugins/filters/
    def config
      @context.registers[:site].config
    end


    def prog_lang(page)
      if page['path'] =~ %r{^(\w\w)/(\w+)/}
        $2
      else
        nil
      end
    end

    
    # Return the two-letter ISO 639-1 language code for the given page.
    # Check the root path for the language code, otherwise use the
    # `i18n.lang` value from `_config.yml`. Finally, default to `en`.
    def iso_639(page)
      if page['path'] =~ %r{^(\w\w)/}
        $1
      else
        config.dig('i18n', 'lang') || 'en'
      end
    end
end

I use these in a template to get the language like this:

{{ page | iso_639 }}

I have tackled this issue a while ago when I was making a multilingual version of the template I use for my site. I even wrote about it so I don’t forget how to do it too.