Step 4.3 – Use “personalized” controllers and methods for a multilanguage site in CodeIgniter

(created at: February 9, 2015; last update: December 2, 2015)
Once we’ve created the infrastructure so that the language is automatically passed to our controllers, is time to “personalize” the name of the controllers and methods according to the language used.

Taking into consideration that the standard url would be http://example.com/fr/controller/method we could of course duplicate all our controllers inside some sort of language directories (application/controllers/fr/controller_in_french, application/controllers/ro/controller_in_romanian), but that would just be too hard on the long run: when you will change something inside a controller, you would have to make the same changes in all controllers of different languages.

So why not do something that will allow us to send all requests, no matter the language to the same controllers, the difference being that when working with the database tables, it will only ask for info in its own language.

But we will have to leave the users the impression that they are accessing a language specific url. What do I mean by this? If in english someone is asking to see all posts for a certain category it will go to http://example.com/category/name_of_category. Now, if someone is asking to see all posts for a certain category in french, he/she will have to go to http://example.com/fr/categorie/name_of_category, but behind the scene he/she will actually be served by the Category.php controller.

To do this we will work inside the application/config/development/routes.php.

First of all, we associate “controllers” and “methods” of other languages to the controllers and methods we have defined (this one is done manually, unless you think of another method):

$controllers_methods = array(
  'de' => array(
    'willkommen/list' => 'welcome/list',
    'willkommen' => 'welcome'
  ),
  'fr' => array(
    'bienvenu/list' => 'welcome/list',
    'bienvenu' => 'welcome'
  )
);

The thing is that, when you write the uris you must write the biggest uris first (the ones that have methods attached to controllers), and leave the shortest ones (the ones that have only controllers) at the end.

Now, instead of just calling the controller as we did in previous tutorial, we just return a callback function when someone asks for a controller and method in a particular language:

$route['^(\w{2})/(.*)'] = function($language, $link) use ($controllers_methods)
{
  foreach($controllers_methods[$language] as $key => $sym_link)
  {
    if(strrpos($link, $key,0) !== FALSE)
    {
      $new_link = ltrim($link,$key);
      $new_link = $sym_link.$new_link;
      break;
    }
  }
  return $new_link;
};
$route['^(\w{2})$'] = $route['default_controller'];

So, in the end the router.php would look something like this:

<?php

defined('BASEPATH') OR exit('No direct script access allowed');

$route['default_controller'] = 'welcome';
$route['404_override'] = '';
$route['translate_uri_dashes'] = TRUE;

$route['admin'] = 'admin/dashboard';

$controllers_methods = array(
  'de' => array(
      'willkommen/list' => 'welcome/list',
      'willkommen' => 'welcome'
    ),
  'fr' => array(
      'bienvenu/list' => 'welcome/list',
    '  bienvenu' => 'welcome'
    )
);

$route['^(\w{2})/(.*)'] = function($language, $link) use ($controllers_methods)
{
  if(array_key_exists($language,$controllers_methods))
  {
    foreach($controllers_methods[$language] as $key => $sym_link)
    {
      if(strrpos($link, $key,0) !== FALSE)
      {
        $new_link = ltrim($link,$key);
        $new_link = $sym_link.$new_link;
        break;
      }
    }
    return $new_link;
  }
  return $link;  
};
$route['^(\w{2})$'] = $route['default_controller'];

Well… We did it. We finished the multilanguage site in CodeIgniter. Questions?

17 comments

  1. Sorry for the silly question…but what does exactly mean $route[‘^(\w{2})$’] or, better, what’s the purpose of that regular expression?
    Letterally it should mean a string starting with a word of two letters till the end of the string…but I don’t understand the purpose of using that expression.
    Thanks for any feedback

    1. That means that when someone changes language, the application won’t start to look for a controller that has two letters and then output a 404. With this route, the application will know that whatever link has only two letters, it will be directed to the default controller (Welcome.php). The Welcome.php, extending the MY_Controller, will know what language is asked for and output the content accordingly.

  2. Hello! Really great articles (Will try today at home!), help me a lot to understand Codeigniter features, I really miss quality articles like yours for CI3.

    I just have one question: how can I do to set a default language, to use when there’s no “/fr/” or “/de/” in the URL?

    Thanks a lot!

    1. Hello. If you followed all the episodes, you must have got to the part where you set up the languages. In there there is a checkbox that will let you set the default language when you insert or edit languages. If you set one as default that will be taken as default and won’t need anything else to be appended to the url.

  3. Sorry Adrian, I still cannot understand if and how this great Language system can use default CI3 Language system. I mean…to load languages files…what I have to do?…
    Thanks

  4. Question about routing controllers and methods to use the language selected. I was testing one for Spanish. I have if they go to ‘../es/bienvendia’ it goes to the welcome page just fine. But then if I go to say ‘../es/admin’ it goes to a 404 error page. How do I get it to work if I don’t have a controller or method not listed in the $controllers_method array? Or do I now have to add to the array every controller/method I want to use for that language?

    1. Hello… sorry about that. In the previous tutorial I’ve written a line especially for that, but it seems that during this episode I forgot to put that line again. Just before: “$route[‘^(\w{2})$’] = $route[‘default_controller’];” you must insert: “$route[‘^(\w{2})/(.*)$’] = ‘$2’;”. I’ve modified this tutorial’s code too. Thank you for noticing.

      1. Sorry again. I added the line but it is now saying that $new_link is not a variable, which would make since if there is not link in the $controllers_methods array. So I tried to move the ‘return $new_link;’ where the ‘break’ is in the foreach, that removed the error, but then still only directed me to the default_controller.

        For every link i add to the $controllers_method it works, but I am wanting to make sure that it does not break if I do not add a link to the array. So using Admin/Users as an example, and not adding it to the array, it only directs to the Welcome controller (default_controller).

        Any help is appreciated.

        1. You are right about your assumption. The first thing to do before iterating through $controller_methods is to see if there is a $controllers_methods having the language slug as key. Will update the tutorial in 10 minutes.

  5. Hi, nice tutorials; im learing a lot with those great tutorials you made.

    i have a few questions:

    i want to know how can i made a custom $rotute config; so it will take anything like:
    it/controller/mehtod
    en/controller/metod
    controller/method

    without need to configure the $controllers_methods you have; do you know something like this?

  6. i already did my last question; i just want to know how i can put a folder in the sintax something like:

    [code]
    $route[‘^(\w{2})/(.*)/(.*)’] = function($language, $folder, $link)
    [/code]
    so i can call something like:
    en/folder/mycontroller/mehtod
    en/mycontroller/method

  7. Wow, just when I thought I’d exhausted all the online tutorials on Codeigniter, I find a new one – and one that gives me something I can actually use, and with an updated version of CI. I’ve completed the Ion Auth and the CMS tutorials because they are something I can use for my own projects. Thanks, Adrian.

    PS: I note that there are a lot of controller files (with matching model files). Could the CMS project for example be extended into an HMVC framework? I am looking for tutorials on HMVC with Codeigniter and there are not a lot…

    PPS: you and Cristian Darie are my heroes

  8. Hello all, to Fionn’s question, I am an enthusiast of hmvc and am converting the cms here being developed into hmvc. So far, i have a working admin but i am not sure i can post the tutorial as this our hero did here, however, i got to try when i am do and make due reference here.
    Thanks to Mr. Avenir for his wonderful tutorials

Leave a Reply

Your email address will not be published. Required fields are marked *

No spam? * Time limit is exhausted. Please reload CAPTCHA.