All Projects → mrzool → polyglot-jekyll

mrzool / polyglot-jekyll

Licence: MIT license
Plugin-free multilanguage Jekyll websites

Programming Languages

HTML
75241 projects

Projects that are alternatives of or similar to polyglot-jekyll

front
Frontmatter
Stars: ✭ 21 (-54.35%)
Mutual labels:  yaml, frontmatter
Gray Matter
Contributing Pull requests and stars are always welcome. For bugs and feature requests, please create an issue.
Stars: ✭ 2,105 (+4476.09%)
Mutual labels:  yaml, frontmatter
remark-frontmatter
remark plugin to support frontmatter (YAML, TOML, and more)
Stars: ✭ 167 (+263.04%)
Mutual labels:  yaml, frontmatter
ryaml
Python yaml library using Rust
Stars: ✭ 14 (-69.57%)
Mutual labels:  yaml
dynamic.yaml
DEPRECATED: YAML-based data transformations
Stars: ✭ 14 (-69.57%)
Mutual labels:  yaml
yaml.nvim
🍒 YAML toolkit for Neovim users
Stars: ✭ 81 (+76.09%)
Mutual labels:  yaml
ufw
A minimalist framework for rapid server side applications prototyping in C++ with dependency injection support.
Stars: ✭ 19 (-58.7%)
Mutual labels:  yaml
AUCR
Analyst Unknown Cyber Range - a micro web service framework
Stars: ✭ 24 (-47.83%)
Mutual labels:  yaml
codemagic-sample-projects
A collection of sample apps built with Codemagic CI/CD. Please see the codemagic.yaml file for a sample workflow configuration.
Stars: ✭ 82 (+78.26%)
Mutual labels:  yaml
yaml-editor
Edit YAML and see it processed by various processors
Stars: ✭ 29 (-36.96%)
Mutual labels:  yaml
Guice-configuration
Guice configuration module allows inject values from files as JSON, HOCON and Properties format
Stars: ✭ 28 (-39.13%)
Mutual labels:  yaml
jekyll frontmatter tests
A Jekyll plugin to test frontmatter on posts and other documents in a Jekyll site.
Stars: ✭ 28 (-39.13%)
Mutual labels:  frontmatter
vscode-yaml-sort
This VS Code extension exposes the possibility to sort, format and validate yaml files.
Stars: ✭ 25 (-45.65%)
Mutual labels:  yaml
pipeline
Spline is a tool that is capable of running locally as well as part of well known pipelines like Jenkins (Jenkinsfile), Travis CI (.travis.yml) or similar ones.
Stars: ✭ 29 (-36.96%)
Mutual labels:  yaml
cfg-rs
A Configuration Library for Rust Applications
Stars: ✭ 18 (-60.87%)
Mutual labels:  yaml
elk
🦌 Minimalist yaml based task runner
Stars: ✭ 43 (-6.52%)
Mutual labels:  yaml
smacha
SMACHA is a meta-scripting, templating, and code generation engine for rapid prototyping of ROS SMACH state machines.
Stars: ✭ 15 (-67.39%)
Mutual labels:  yaml
gohit
Run curl commands from yaml files
Stars: ✭ 19 (-58.7%)
Mutual labels:  yaml
bafi
Universal JSON, BSON, YAML, CSV, XML converter with templates
Stars: ✭ 65 (+41.3%)
Mutual labels:  yaml
cryptorious
CLI Password Manager
Stars: ✭ 15 (-67.39%)
Mutual labels:  yaml

Polyglot Jekyll

"Make it small. Make it dead simple." —Adam Morse

Polyglot Jekyll serves both as starting point for building a multilanguage website in vanilla Jekyll, and as instructional demo for my approach.

The boilerplate code is intentionally bare-bone, just the few files necessary for Jekyll to build the website and minimal CSS for the demo. There's no build dependency except for Jekyll, no SASS compiling, no browser-sync, no gulpfile.js, no package.json.

Just clone the repo and run jekyll build to build locally.

The approach

The underlying principle is a well-known, universally applicable best practice: separation of content from presentation. Jekyll allows to extract a layout into separated files that support basic logic through the Liquid templating engine.

With Jekyll, the file system structure is the website structure. We deal with multilanguage content by mirroring our site's structure in language-dedicated directories. Our default language will be at the root level, and every other language we want to support will have its own directory. Here's how a basic structure might look:

---------------------------------
   FILE SYSTEM  |  URL STRUCTURE
---------------------------------
 index.md       |   /            
 about.md       |   /about       
 contact.md     |   /contact     
 de/            |                
 ├── index.md   |   /de          
 ├── about.md   |   /de/about    
 └── contact.md |   /de/contact  
 it/            |                
 ├── index.md   |   /it          
 ├── about.md   |   /it/about    
 └── contact.md |   /it/contact  

Note: permalink: pretty needs to be set in _config.yml for the URL structure to be generated as above.

Once we have our starting structure set up, we need to set some metadata in every page using the YAML frontmatter. Besides the usual variables like layout and title, we need to set a language in every page and a handle in every page other than index pages:

---
# In /about.md:
layout: default
title: About
language: en
handle: /about # same as in /de/about.md and /it/about.md
---

The reason for these two extra variables will become clear in a moment. Now let's deal with the content.

Site-wide content

We put content that needs to present across the whole website (like the one you typically find in header and footer) in our _config.yml file. Dealing with strings in different languages is possible with a hash:

# In _config.yml
description: 
  en: Plugin-free multilanguage Jekyll websites
  de: Plugin-freie vielsprachige Jekyll Webseiten
  it: Siti multilingue in Jekyll, senza plugin.

We then use Liquid's bracket notation in the layout file to access the values in our hash. The language variable in the current page's frontmatter ensures that we grab the correct string from _config.yml:

<!-- Data from _config.yml get stored in the `site` global variable -->
<meta name="description" content="{{ site.description[page.language] }}">

Page-specific content

With the structure described above is simple to add copy to every page, just write it in markdown in every file after the frontmatter, and use the special variable {{ content }} to grab it from the layout file.

You often need something more flexible for your average website though. You probably have boxes, buttons, forms and other UI elements, or images with alt texts that also need translation. You can deal with this by expanding the frontmatter in the single page files with the variables you need:

# In /index.md
see-on-github: See on GitHub
tweet-this: Tweet this
# In /de/index.md
see-on-github: Auf GitHub sehen
tweet-this: Twittern
# In /it/index.md
see-on-github: Vedi su GitHub
tweet-this: Twitta

Thanks to this method, we can keep our layout file nice and tidy:

<!-- Data from page files get stored in the `page` global variable -->
<a class="button" href="#">{{ page.see-on-github }}</a>
<a class="button" href="#">{{ page.tweet-this }}</a>

The system described above is incredibly flexible and will cover most of the use cases.

Navigation

Dealing with a navigation menu is a simple matter. But, since our website has every page mirrored for every language, we need to add a conditional in the for loop to make sure that only the pages in the page's current language get picked up, otherwise Jekyll will happily include every page in our project without regard to the language.

<nav>
  {% for p in site.pages %}
    {% if p.language == page.language %} 
      <a href="{{ p.url | prepend: site.baseurl }}">
        {{ p.title }}
      </a>
    {% endif %}
  {% endfor %}
</nav>

Language switch

The language switch is slightly trickier to implement. Let's get the easy part out of the way first. Here's how we deal with switching language from an index page (i.e. a homepage):

<nav class="language-switcher">
  {% if page.name contains "index" %}
    <a href="{{ site.baseurl }}/">EN</a>
    <a href="{{ site.baseurl | append: "/de" }}">DE</a>
    <a href="{{ site.baseurl | append: "/it" }}">IT</a>
  {% endif %}
</nav>

Since index pages sit at the first level of their directories, we just need to append the language to the base url. But what if we want to switch language while being on another page? That's where our handle variable in the frontmatter comes into play:

<nav class="language-switcher">
  {% if page.name contains "index" %}
    <a href="{{ site.baseurl }}/">EN</a>
    <a href="{{ site.baseurl | append: "/de" }}">DE</a>
    <a href="{{ site.baseurl | append: "/it" }}">IT</a>
  {% else %}
    <a href="{{ site.baseurl | append: page.handle }}">EN</a>
    <a href="{{ site.baseurl | append: "/de" | append: page.handle }}">DE</a>
    <a href="{{ site.baseurl | append: "/it" | append: page.handle }}">IT</a>
  {% endif %}
</nav>

On every page other than index pages, every switch link gets the language and the page handle appended. If we're on the page with the /about handle, the generated HTML will look like so:

<a href="/about">EN</a>
<a href="/de/about">DE</a>
<a href="/it/about">IT</a>

Note: In navigation and language switch, you only need the prepend: site.baseurl bit if your site that doesn’t sit at the root of the domain. See this to learn why.


This wraps up our brief excursus of Polyglot Jekyll. Make sure to clone this repo and experiment with it locally to get a hang of how everything works together. If you want to check out the final result, have a look at the online demo.

The approach should be solid enough and easily extensible to more complex websites. The next time you need to build a multilingual website, give it a shot. You might find that you don't need PHP, CMS's and databases to deal with it after all.

Resources

  • Still new to Jekyll? The official docs are the best place to start.
  • When you feel a bit more comfortable, this cheat sheet put together by CloudCannon is the go-to reference for all things Jekyll.
  • YAML is a flexible and powerful syntax to structure your data. Here's the best overview available.
  • To go in-depth into the Liquid templating engine, check out Shopify's official reference or these docs.

License

MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].