Multilanguage Routing by URL key

Hello everyone!
I’m writing this question because I tried to follow the docs and the advices in the other forum thread without success.
I’m setting up a multilanguage site (‘it’ as default, ‘en’ and ‘de’) with the following folder structure:

  • home
  • error
  • Page1
    • Page1Subpage1
    • Page1Subpage2
  • Page2
    • Page2Subpage1
    • Page2Subpage2

I’m setting for each page a proper URL Key and everything is perfect. My problem is that I would like to make all the pages act as a first level page. Page1 and Page2 are only containers, but and i would like to mantain them because of the number of final pages.
Following the docs i tried to set up these routes:

c::set('routes', array(
  array(
    'pattern' => '(:any)',
    'action'  => function($uid) {

      $page = page($uid);

      if(!$page) $page = page('page1/' . $uid);
      if(!$page) $page = page('page2/' . $uid);
      if(!$page) $page = site()->errorPage();

      return site()->visit($page);

    }
  ),
  array(
    'pattern' => array(
    
      'page1/(:any)', 
      'en/page1/(:any)',
      'de/page1/(:any)',
      
      'page2/(:any)', 
      'en/page2/(:any)',
      'de/page2/(:any)'),
      
    'action'  => function($uid) {
      go($uid);
    }
  )
));

This doesn’t work, because I’m getting the URL Key, not the UID. I tried to get the page with these routes but i doesn’t work:

c::set('routes', array(
  array(
      'pattern' => '(:any)',
      'action'  => function($urlkey) {
  
        $page = site()->findBy('urlkey', $urlkey);

        if(!$page) $page = site()->errorPage();
  
        return site()->visit($page);
  
      }
    ),
  array(
    'pattern' => array(
    
      'page1/(:any)', 
      'en/page1/(:any)',
      'de/page1/(:any)',
      
      'page2/(:any)', 
      'en/page2/(:any)',
      'de/page2/(:any)'),
      
    'action'  => function($uid) {
      go($uid);
    }
  )
));

I understand that I’m not getting the right page object and that I should pass the right language code to the ‘site()->visit($page)’ function.
If needed, I could do a compromise and keep the language code in my urls (ex. domain.com/en/Page1Subpage1)… But I cannot find a solution, so I’m here to ask for advices :slight_smile:
Thanks to everyone for the help!

Have you checked out this thread?

Wow! Thank you!
I searched for route-related threads and I missed that one.
It works perfectly, but I can’t get the home page. I tried to put a check in the $visitRoute function, imagining that if I visit domain.com/en the $uid variable would be undefined, but it doesn’t works.
My code:

$visitRoute = function($uid) {
  
//  if ($uid == '') {
//    $uid = 'home';
//  }

  if (!$uid) {
    $uid = 'home';
  }

  $site = site();
  $lang = kirby()->route->lang;
  $page = $site->visit($uid, $lang);

  if($page === $site->errorPage()) $page = $site->visit('page1/' . $uid, $lang);
  if($page === $site->errorPage()) $page = $site->visit('page2/' . $uid, $lang);

  return $page;

};

As a solution I’ve added two more routes that match the translated home pages, so my full code is:

$visitRoute = function($uid) {

  $site = site();
  $lang = kirby()->route->lang;
  $page = $site->visit($uid, $lang);

  if($page === $site->errorPage()) $page = $site->visit('page1/' . $uid, $lang);
  if($page === $site->errorPage()) $page = $site->visit('page2/' . $uid, $lang);

  return $page;

};

c::set('routes', array(
  array(
    'pattern' => '(?:page1|page2)/(:any)',
    'action'  => function($uid) {
      go($uid);
    }
  ),
  array(
    'pattern' => '(?:en/page1|en/page2)/(:any)',
    'action'  => function($uid) {
      go('en/' . $uid);
    }
  ),
  array(
    'pattern' => '(?:de/page1|de/page2)/(:any)',
    'action'  => function($uid) {
      go('de/' . $uid);
    }
  ),
  array(
    'pattern' => 'en',
    'action' => function () {
      return site()->visit('home', 'en');
    }
  ),
  array(
    'pattern' => 'en/(:any)',
    'action'  => $visitRoute,
    'lang'    => 'en'
  ),
  array(
    'pattern' => 'de',
    'action' => function () {
      return site()->visit('home', 'de');
    }
  ),
  array(
    'pattern' => 'de/(:any)',
    'action'  => $visitRoute,
    'lang'    => 'de'
  ),
  array(
    'pattern' => '(:any)',
    'action'  => $visitRoute,
    'lang'    => 'it'
  )
));

Bu I still have two questions:

  1. Is there a cleaner way to check for the translated home pages?
  2. Am I correct in thinking that the routes follow a principle of “first match”? I didn’t find mention about that in the docs (and I’m not so prepared in back-end code if it isn’t still clear :slight_smile: