├── .gitignore ├── LICENSE ├── README.md ├── _config.yml ├── _layouts └── default.html ├── about.md ├── de ├── about.md └── index.md ├── index.md ├── it ├── about.md └── index.md └── preview.png /.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Mattia Tezzele 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Polyglot Jekyll 2 | 3 | > "Make it small. Make it dead simple." —Adam Morse 4 | 5 | Polyglot Jekyll serves both as starting point for building a multilanguage website in vanilla Jekyll, and as instructional demo for my approach. 6 | 7 | The boilerplate code is intentionally bare-bone, just the few files necessary for Jekyll to build the website and minimal CSS for the [demo](http://mrzool.cc/polyglot-jekyll). There's no build dependency except for Jekyll, no SASS compiling, no browser-sync, no `gulpfile.js`, no `package.json`. 8 | 9 | Just clone the repo and run `jekyll build` to build locally. 10 | 11 | ## The approach 12 | 13 | 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. 14 | 15 | 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: 16 | 17 | ``` 18 | --------------------------------- 19 | FILE SYSTEM | URL STRUCTURE 20 | --------------------------------- 21 | index.md | / 22 | about.md | /about 23 | contact.md | /contact 24 | de/ | 25 | ├── index.md | /de 26 | ├── about.md | /de/about 27 | └── contact.md | /de/contact 28 | it/ | 29 | ├── index.md | /it 30 | ├── about.md | /it/about 31 | └── contact.md | /it/contact 32 | ``` 33 | 34 | **Note**: *`permalink: pretty` needs to be set in `_config.yml` for the URL structure to be generated as above.* 35 | 36 | 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: 37 | 38 | ```yaml 39 | --- 40 | # In /about.md: 41 | layout: default 42 | title: About 43 | language: en 44 | handle: /about # same as in /de/about.md and /it/about.md 45 | --- 46 | ``` 47 | 48 | The reason for these two extra variables will become clear in a moment. Now let's deal with the content. 49 | 50 | ### Site-wide content 51 | 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: 52 | 53 | ```yml 54 | # In _config.yml 55 | description: 56 | en: Plugin-free multilanguage Jekyll websites 57 | de: Plugin-freie vielsprachige Jekyll Webseiten 58 | it: Siti multilingue in Jekyll, senza plugin. 59 | ``` 60 | 61 | 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`: 62 | 63 | ```liquid 64 | 65 | 66 | ``` 67 | 68 | ### Page-specific content 69 | 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. 70 | 71 | 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: 72 | 73 | ```yaml 74 | # In /index.md 75 | see-on-github: See on GitHub 76 | tweet-this: Tweet this 77 | # In /de/index.md 78 | see-on-github: Auf GitHub sehen 79 | tweet-this: Twittern 80 | # In /it/index.md 81 | see-on-github: Vedi su GitHub 82 | tweet-this: Twitta 83 | ``` 84 | 85 | Thanks to this method, we can keep our layout file nice and tidy: 86 | 87 | ```liquid 88 | 89 | {{ page.see-on-github }} 90 | {{ page.tweet-this }} 91 | ``` 92 | 93 | The system described above is incredibly flexible and will cover most of the use cases. 94 | 95 | ### Navigation 96 | 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. 97 | 98 | ```liquid 99 | 108 | ``` 109 | 110 | ### Language switch 111 | 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): 112 | 113 | ```liquid 114 | 121 | ``` 122 | 123 | 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: 124 | 125 | ```liquid 126 | 137 | ``` 138 | 139 | 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: 140 | 141 | ```html 142 | EN 143 | DE 144 | IT 145 | ``` 146 | 147 | **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](https://byparker.com/blog/2014/clearing-up-confusion-around-baseurl/) to learn why.* 148 | 149 | --- 150 | 151 | 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](http://mrzool.cc/polyglot-jekyll/). 152 | 153 | 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. 154 | 155 | ## Resources 156 | 157 | - Still new to Jekyll? The [official docs](https://jekyllrb.com/docs/home/) are the best place to start. 158 | - When you feel a bit more comfortable, this [cheat sheet](http://jekyll.tips/jekyll-cheat-sheet/) put together by [CloudCannon](http://cloudcannon.com/) is the go-to reference for all things Jekyll. 159 | - YAML is a flexible and powerful syntax to structure your data. Here's the [best overview](https://learnxinyminutes.com/docs/yaml/) available. 160 | - To go in-depth into the Liquid templating engine, check out Shopify's [official reference](https://help.shopify.com/themes/liquid) or these [docs](https://shopify.github.io/liquid/). 161 | 162 | 163 | ## License 164 | [MIT](LICENSE) 165 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | name: 2 | en: Polyglot Jekyll 3 | de: Polyglottes Jekyll 4 | it: Jekyll poliglotta 5 | description: 6 | en: Plugin-free multilanguage Jekyll websites 7 | de: Plugin-freie vielsprachige Jekyll Webseiten 8 | it: Siti multilingue in Jekyll, senza plugin. 9 | footer: 10 | en: An open-source project by [mrzool](http://mrzool.cc) 11 | de: Ein open-source Projekt von [mrzool](http://mrzool.cc) 12 | it: Un progetto open-source di [mrzool](http://mrzool.cc) 13 | exclude: [README.md] 14 | permalink: pretty 15 | repository: mrzool/polyglot-jekyll 16 | baseurl: /polyglot-jekyll 17 | -------------------------------------------------------------------------------- /_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ page.title }} | {{ site.name[page.language] }} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 32 | 43 | 44 |
45 |

{{ site.name[page.language] }}

46 |

{{ site.description[page.language] }}

47 |
48 | 49 |
50 | {{ content }} 51 |
52 | 53 | {% if page.name contains "index" %} 54 |
55 | {{ page.see-on-github }} 56 | {{ page.tweet-this }} 57 |
58 | {% endif %} 59 | 60 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /about.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: About 4 | language: en 5 | handle: /about 6 | nav-order: 2 7 | --- 8 | 9 | There's no need to use a CMS to build a multilingual website, Jekyll can handle that just fine. 10 | 11 | By making considered use of layouts, YAML frontmatter, and Liquid templating capabilities, it's possible to abstract content from presentation and keep your project tidy and maintainable. 12 | 13 | Curios about how it all works? Check out source and README on [GitHub](https://github.com/mrzool/polyglot-jekyll). 14 | -------------------------------------------------------------------------------- /de/about.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Infos 4 | language: de 5 | handle: /about 6 | nav-order: 2 7 | --- 8 | 9 | Es ist nicht unbedingt nötig, ein CMS zu verwenden, um ein vielsprachiges Website zu erstellen, Jekyll kann damit schon gut umgehen. 10 | 11 | Durch geschickte Nutzung von Layouts, YAML Frontmatter, und Liquid Templating-Fähigkeiten, ist es möglich, Inhalte von deren Darstellung zu trennen um deinen Projekt ordentlich und wartbar zu behalten. 12 | 13 | Neugierig darauf, wie das funktioniert? Checke Quellcode und README auf [GitHub](https://github.com/mrzool/polyglot-jekyll) aus. 14 | -------------------------------------------------------------------------------- /de/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Startseite 4 | language: de 5 | nav-order: 1 6 | see-on-github: Auf GitHub sehen 7 | tweet-this: Twittern 8 | --- 9 | 10 | Probiere es einfach aus. Hast du schon mal eine Webseite gesehen, die so schnell zwischen Sprachen wechselt? Eben, ich auch nicht. 11 | 12 | 13 | -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Home 4 | language: en 5 | nav-order: 1 6 | see-on-github: See on GitHub 7 | tweet-this: Tweet this 8 | --- 9 | 10 | Go ahead and try it. Have you ever seen a website switch language that fast? Yeah, me neither. 11 | -------------------------------------------------------------------------------- /it/about.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Info 4 | language: it 5 | handle: /about 6 | nav-order: 2 7 | --- 8 | 9 | Non c'è bisogno di usare un CMS per sviluppare un sito multilingue, Jekyll è perfettamente in grado di gestire la cosa. 10 | 11 | Facendo un uso ragionato di layouts, YAML frontmatter, e delle capacità di templating che ha Liquid, è possibile separare i contenuti dalla presentazione così da rendere il tuo progetto ordinato e mantenibile. 12 | 13 | Curioso su come funziona? Dai un'occhiata al sorgente e al README su [GitHub](https://github.com/mrzool/polyglot-jekyll). 14 | -------------------------------------------------------------------------------- /it/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Home 4 | language: it 5 | nav-order: 1 6 | see-on-github: Vedi su GitHub 7 | tweet-this: Twitta 8 | --- 9 | 10 | Provalo. Hai mai visto un sito cambiare lingua così velocemente? Nemmeno io. 11 | 12 | 13 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrzool/polyglot-jekyll/f68a8275d382abf31f3c02690cb79f75eb6a4d67/preview.png --------------------------------------------------------------------------------