Routing Multi Language Multi Region

Hi All,

i like to do a multilanguage-multiregion-site, but i have no clue how i can do the routing.

as an example i like to have three languages in kirby via the basic multilanguage setup: en, de, fr
only these language-sites are available to edit via panel/texteditor, but i also need an indicator for the region of the user. this should be done via an select-field for language and country, which links to an url with the lang-region-code.
default lang should be ‘en’ with no lang-region-slug.
if no region is selected, only the language-code should route to the desired page.
if a region is available, this should be stored in a session/cookie and the page-template have to be able to react to that in some way.

so the resulting urls can be something like this:

mydomain.com/ -> home
mydomain.com/about -> about
mydomain.com/about/team -> about/team

mydomain.com/en/ -> home
mydomain.com/en/about -> about
mydomain.com/en/about/team -> about/team

mydomain.com/en-us/ -> home
mydomain.com/en-us/about -> about
mydomain.com/en-us/about/team -> about/team

mydomain.com/de -> start
mydomain.com/de/ueber-uns -> ueber-uns
mydomain.com/de/ueber-uns/team ->  ueber-uns/team

mydomain.com/de-de -> start
mydomain.com/de-de/ueber-uns -> ueber-uns
mydomain.com/de-de/ueber-uns/team ->  ueber-uns/team

mydomain.com/de-ch -> start
mydomain.com/de-ch/ueber-uns -> ueber-uns 

mydomain.com/fr-fr -> maison
mydomain.com/fr-fr/sur -> sur
mydomain.com/fr-fr/sur/equipe ->  sur/equipe

mydomain.com/fr-ch -> maison
mydomain.com/fr-ch/sur -> sur 
mydomain.com/fr-ch/sur/equipe ->  sur/equipe

#1 how to route ‘lang-region-codes’ to ‘lang-pages’? also with the default uri?
#2 how to save the region to a session or cookie, so the template can react in some way?
#3 how to auto-redirect on first visit to lang-region?

If someone is experienced with that, it would be really nice to get some help or hints.
Tnx!

#1 Routes should work like this:

c::set('routes', [
  [
    'pattern' => 'de-de',
    'action'  => function() {
      return site()->visit('/', 'de');
    },
  ],
  [
    'pattern' => 'de-de/(:all)',
    'action'  => function($all) {
      return site()->visit($all, 'de');
    },
  ],
  [
    'pattern' => 'en',
    'action'  => function() {
      return site()->visit('/', 'en');
    },
  ],
  [
    'pattern' => 'en/(:all)',
    'action'  => function($all) {
      return site()->visit($all, 'en');
    },
  ],
  [
    'pattern' => 'en-us',
    'action'  => function() {
      return site()->visit('/', 'en');
    },
  ],
  [
    'pattern' => 'en-us/(:all)',
    'action'  => function($all) {
      return site()->visit($all, 'en');
    },
  ],
]);

#2 Is this necessary? I guess you want to pass some data to the template, but you can do that within the array.

#3: I’m afraid I don’t understand what you mean.

1 Like

Hey Texnixe, you are always so fast. That’s great! Also on a Saturday! :slight_smile:

I am still quite new to kirby, especially to the backend-stuff like routing.

#1
I guess this goes to the config.php.
How would you make this a bit more dynamic. In theory there could be 100 regions and more languages.
Also with the default language ‘domain.com’ without a slug…

#2
You’re right. The only thing i need is to parse the region-code to the template, so that dependent on a specific region, i can change some link-target f.e. how can i add params to the array?

#3
so i mean, if the user speaks german and lives in germany, i will redirect him to mydomain.com/de-de on his first visit. maybe by reading the accept-language header or cookie-settings or …

tnx!

#1 yes, it goes into the config file. You don’t have to do anything special for the default slug. As regards making it more dynamic, well, yes, for the different regions that belong to a language, you can use some regex voodoo, I guess.

What is your purpose of using regions? Do you show different content per region? Otherwise, you would end up with a lot of duplicated content under different URLs…

#2 You can’t use parameters in routes, they are ignored.

depending on the region, there is a different behavior within a button or a form, but the content is the same.
only sites in en, de, fr are editable by the editor, but for example if the region ist fr-ca, a shop-button does not link to the shop, but to a new distributor-site in canada for example…

i guess you mean under the same domain?
i like to avoid that by giving the alternate hreflang. so it should not be a prob with duplicated contents for SEO i think

<link href="https://www.mydomain.com/fr-ch" rel="alternate" hreflang="fr-ch">
<link href="https://www.mydomain.com/en-ca" rel="alternate" hreflang="en-ca">
....

i wont. i understood that i can pass some data to the template and can do that within the array. see your first answer.
but how?

See the docs, under Returning a page with additional data for the template

I meant the same content under different URLs. But yes, makes sense.

i tried returning the page with additional data like the docs describes for multilanguage-sites


Example #1

like in the docs, i get the following error with kirby 2.5.5

c::set('routes', [
 [
  'pattern' => 'de-de',
  'action'  => function() {
	$data = array(
		'language' => 'de',
		'region' => 'de',
		'foo' => 'bar'
	);
	
	site()->visit('/', 'de');
	return array('/', $data);
  },
],
[
  'pattern' => 'de-de/(:all)',
  ...

Argument 1 passed to Kirby::render() must be an instance of Page, boolean given, called in /var/www/html/web/kirby/kirby/component/response.php on line 27

Example #2

works, if i do the following:

c::set('routes', [
[
  'pattern' => 'de-de',
  'action'  => function() {
	$data = array(
		'language' => 'de',
		'region' => 'de',
		'foo' => 'bar'
	);
	return array( site()->visit('/', 'de'), $data);
  },
],
[
  'pattern' => 'de-de/(:all)',
  ...

i can access the props from $data directly in the template and get the correct output

<div><?= $language . ' - ' . $region . ' - ' . $foo ?></div>

any idea what’s wrong with the first example?
second example works, but is it correct?
no need for a custom controller to access the $data of the router?

if i have a snippet in the template, but the snippet is only able to access the props, if the template hands them over?
is there another way?

 <?php snippet('header', ['region' => $region]) ?>

Thanks!

No, I don’t know why the first version doesn’t work, but the second example is correct, anyway.

No, you don’t need a controller, but in many cases, you will probably have a controller anyway to separate logic from presentation.

It shouldn’t be necessary to pass the variable to the snippet, but you should check if the variable is set, before trying to print it because you might have pages where you include the header but the variable is missing, because you don’t return it from every route?

Thank you very much to pointing me @texnixe
I will try to find out, why it doesn’t pass the props to the snippet and hopefully get some regex-stuff for the router.