Web Development

PJAX + I18N = TROUBLE

What we learned launching our first multilingual PJAX web site

Recently we launched a web site which needed to be multilingual as we expected around 20 % of users not to speak any German at all. And this foreign users shouldn’t be left behind.

For some years now we use PJAX as standard (also sometimes we don’t) on every web site we create. If you never heard of PJAX: it’s AJAX (asynchronous javascript plus x) for every page of your site, works automatically and with a fall-back to a basic http request. Why are we using PJAX at all and add more complexity to our sites source code? Because it can significantly speed up web sites. Which is a benefit for your users, regarding Google bot and therefore you. So you’re gonna want that.

PJAX transfers only that part of a page which is different. Assets like javascripts and stylesheets are not requested again and not even parsed a second time by the browser. So loading and rendering speed up with every page request. If your backend framework supports fragment caching (or you’ve implemented that by yourself as we did), your web site can be fast as hell, which is quite nice.

So, what seems to be the trouble? First of all, all PJAX implementations we know take care of the page title and the browser history, but nothing else. And that’s fine as most people just don’t need anything else. But if you’re dealing with i18n, Google expects you to use hreflang attributes on your web site. On some of your links, your content and – in your <head>, indicating all different language versions of the current page. This is where trouble kicks in, because as Google bot executes javascript, you need to update your <head> on every PJAX page request which PJAX by definition doesn’t.

Sure, you could send that information in your response header, but that didn’t work for us in our production environment. Perhaps we could’ve fixed that somehow, but we decided to go the other way and just update our <head> on every single PJAX page request.

Sounds silly? Sounds like we could’ve just removed PJAX? Of course we didn’t want to update the whole <head>. Just the parts which needed an update. That’s why we added a data attribute to every html element in <head> which needed an update. And removed that on every single PJAX request, replacing with new ones from our fresh PJAX view fragment. Simple as that. And Google seems to like it.