enduro js: manual multilingual sites

enduro js: manual multilingual sites

I am building the new i22 company website utilizing enduro.js cms. For the last 5 or more years, I probably would have taken contao for this job - at i22 we use contao for some projects and it is always fun to work with it. But with our company website we want to try a more lightweight cms, and enduro.js looks promising.

Multilingual Support

Multilingual support out of the box, it says, and it is right. Just type enduro culture add de en fr and every content box is multilingual editable. Enduro uses the culture as path prefix, resulting in URLs like https://www.i22.de/en/jobs/ruby-developer and https://www.i22.de/de/jobs/ruby-developer. And this is, what this post is about.

SEO Relevance

We have a strong look on SEO at i22, and if you too, you know where you have to place keywords to strengthen their seo relevance:

  1. Page Title - it is the most important part google or bing is displaying
  2. Domain Name - eg. we-love.ai, the artificial intelligence theme is part of the domain.
  3. Page Path - maybe you need de/stellenangebote/ruby-entwickler for de-content and en/jobs/ruby-developer for en-content
  4. Meta Description - the excerpt of your contents in the search listing
  5. Human readable content - like headlines, copy, etc...

Meta Data Editor of Ghost Blogging Software

To improve your search rank, a localized path comes in handy.

HTML Lang Attribute

You can add a lang attribute on the html element, and on many other elements. And as I read here: Adding Content-Language on the html element is best practice.
This attribute helps every user agent to understand your content better, for examplge it can provide inplace translations and more.

An other common usage of lang is:

In den Weiten des <abbr lang="en" title="World Wide Web">WWW</abbr>…

That's a german sentence with an english abbreviation, all mark*'ed* up.

HTML Lang Attribute with culture

Using enduros culture feature, you need to build a handlebar helper to access the current culture from the handlebar context:

// /assets/hbs_helpers/current-culture.js
enduro.templating_engine.registerHelper("current-culture", function (obj) {
  return obj.data.root._meta.culture || '';
});

and use it in your body.hbs:

// /components/layout/body.hbs
<!doctype html>
<html lang="{{current-culture}}">
  <head>
    <meta charset="utf-8">
    …

and that's it.

HTML Lang Attribute without culture

Without the culture feature, you should add a meta block to every page object, where you can set the language:

// /cms/index.js
{
  …
  meta: {
    …
    language: '@@global.languages.en'
    …
  },
  …

and in your body.hbs you simply put:

// /components/layout/body.hbs
<!doctype html>
<html lang="{{meta.language}}">
  <head>
    <meta charset="utf-8">
    …

Content Negotiation

Out of the box, enduro redirects every new visitor to the first configured language in the /cms/config/babel.js file. Without the culture feature, you need to do this by yourself (or your express app).

Nearly every browser, tells every web server which language he likes most and second most.

HTTP Accept-Language Header

btw: If you have ever developed a contao page, and did not check the fallback language checkbox, you may have had a blank page as result. This happens because contao uses http headers for content negotiation. If no fallback language is set, it will always try to deliver the perfect localized website.

Luckily, enduro enables you to use the full feature of the underlying express.js app:

// app/app.js 
var local_app = function () {}
…
local_app.prototype.init = function (app) {}
…
module.exports = new local_app()

And by reading the express documentation, I found this information about acceptsLanguages:

req.acceptsLanguages(lang [, ...])

Returns the first accepted language of the specified languages, based on the request’s Accept-Language HTTP header field. If none of the specified languages is accepted, returns false.

// /app/app.js
…
local_app.prototype.init = function (app) {
  app.get('/', function(req, res) {
    const fallbackLanguage = 'en';
    res.redirect(`/${(req.acceptsLanguages('de','en') || fallbackLanguage)}/index`); }); 
  }
  …
}
module.exports = new local_app()

This way, the webserver figures out which version is the best for the visitor, and redirects him. If the language of the visitor is not supported by your website, the visitor is redirected to english language. Only if the user visits your page's webroot /, because I assume, if he is following a deeplink, he does not want to be redirected.

Manual Multilingual Directory Setup

Now build for every language a subdirectory:

// folder structure from /cms
+- global…
+- en/
+-- index.js
+-- jobs/
+---- php-developer.js
|
+- de/
+-- index.js
+-- stellenausschreibung
+---- php-entwickler.js
…

One more benefit of this setup is, you are enabled to use the generators feature on every localized pagetree.

Soon I will write about xml sitemap, metatag handling and pagespeeding for enduro.