Problems getting dynamic routing for multilingual site working


Hi everyone. Just getting started with Ghost. Doing great so far. Love it. Have figure out how to do most things from the docs but I can’t get a full multilingual site running, in spite of reading all the docs multiple times and trying everything I can think of. I can get the translation strings to work fine when I change the publication language in the admin, but I can’t get the dynamic routing to work.

I’m running Ghost version 2.19.3 in a local install on Mac Mojave 10.14.3, node 10.13.0, with a custom theme. This is my routes.yaml file:

    permalink: /
    template: home

    permalink: /blog/{slug}/
    filter: primary_tag:blog
    permalink: /testimonial/{slug}/
    filter: primary_tag:testimonial
    permalink: /fr/{slug}/
    filter: tag:fr
    permalink: /it/{slug}/
    filter: tag:it
    permalink: /ru/{slug}/
    filter: tag:ru

  tag: /tag/{slug}/
  author: /author/{slug}/

I’m confused what I need to do next to get a URL such as /fr/page-slug to load, as currently it returns a 404. The docs say to add this code block to my post.hbs (and I also assume page.hbs) template:

  {{#has tag="fr"}}
    <html lang="fr">
    <html lang="en">

But where does that go? I tried putting it in a few places and nothing happens. Also, I don’t have the html tag in my post and page templates. That tag resides in my default template, and I inherit that in post and page. At any rate, no matter what I do, I can’t even get a single page to load this way and I have no idea what I’m doing wrong. Any advice is greatly appreciated, as I’ve been stuck on this for the past 3 days. Thanks!


Hey @mattbarnicle! Tried reproducing the 404 issue but didn’t have any luck. Could you tell if you are seeing any results are showing up on you /blog/ or /fr/ pages? When you are visiting just the /page-slug URL does the post appear for you? Does any of the pages work when you remove all of the collection but one, for example just leaving the /fr/ route?

Regarding the <html lang=..> issue. First of all, you would need to create a custom template for each language post and identify it for each collection, e.g.:

    permalink: /fr/{slug}/
    filter: tag:fr
    index: fr

Then you would need to have a completely new template with:

<html lang="fr"

Just like it is pointed out in the tutorial:

Note, these have to be complete templates that are not injected into {{body}} of default.hbs (should not use {{!< default}}), otherwise you don’t have access to the top html tag of the page to control the lang attribute.

1 Like

Thanks for the quick reply @gargol. Much appreciated.

/blog/ pages work fine. I can only get the index page to load for /fr/ but no others. Everything else that has a slug underneath fr returns a 404, e.g. /fr/some-page.

Yes, this works fine on all pages.

No, still 404 when I do that.

This works for the index page, but no others.

The tutorial says that the filename should be the name of the language, e.g. fr.hbs. I tried variations of index-fr.hbs,, but the only one that works is fr.hbs. But it doesn’t discuss having language-specific templates for all the other pages, so I don’t understand how this would work. I can’t imagine all pages on the site using the index template.

That’s too bad. I would like to minimize template duplication whenever possible. It seems like there should be a way to check that in the default template using some conditional logic. I couldn’t figure that out, but I did figure out a way to do it by injecting the language in a contentFor block in the fr.hbs template and using that injected block in the default template. That works fine it seems.


For the sake of eliminating potential issues caused by changes I might have made in my install, I created a fresh install to see if I could get this to work, and encountered the same problems. Here are the steps I took:

  • Install a new instance via ghost install local in a different folder
  • Add fr collection to routes file:
    permalink: /{slug}/
    template: index
    permalink: /fr/{slug}/
    filter: tag:fr
  • Create a new page with title “Test page - French enabled?”.
  • Restart ghost
  • Navigate to URL /fr/test-page-french-enabled/
  • 404 error

Am I doing anything wrong in this process?

I also tried the above steps with this modification to routes and it still didn’t work:

    permalink: /{slug}/
    template: index
    permalink: /fr/{slug}/
    filter: tag:fr
    index: fr

Also signed up to ask about this… Seems like pretty essential functionality.