phpkohana-3.3

Kohana 3.3.3 multi language site


I'm new to Kohana, using version 3.3.3.1, I'm trying to build a simple dynamic site with the content/pages stored in mySQL DB. The site should have multiple languages. I tried searching everywhere for a good solution/module but I couldn't find anything that works with latest version of Kohana. I tried also this: https://github.com/shockiii/kohana-multilang but it's not working on the latest kohana.

I want to put the language in URL like this (and possibly hide the parameter for the default language):

http://www.domain.com/topics/page-name-here.html   -- this would be default EN
http://www.domain.com/de/test/some-page-name-here.html
http://www.domain.com/fr/category/other-page-name-here.html

In my bootstrap.php I have the following route (before adding the language logic):

Route::set('page', '(<category>)(/<pagename>.html)', array(
    'category' => '.*', 
    'pagename' => '.*'))
    ->defaults(array(
                'controller' => 'Page',
                'action' => 'index',
)); 

I want to have all this multi-language logic inside a module if possible. But I read about overriding the Request, URL, Route, and other classes to be able to do that.

What is the best way I can do this? What should I do/change and where to start?

I know this is more a general question, but any help or guidance is greatly appreciated.

Thanks very much!


Solution

  • 1) add <lang> into routes in bootstrap.php:

    Route::set('default', '((<lang>)(/)(<controller>)(/<action>(/<id>)))', array('lang' => "({$langs_abr})",'id'=>'.+'))
        ->defaults(array(
            'lang'          => $default_lang,
            'controller'    => 'Welcome',
            'action'        => 'index',
        ));
    

    - define $default_lang somehow - I use siteconfig.php file placed inside application/config -see below.

    2) Extend/redefine factory method in Request Controller:

    <?php defined('SYSPATH') or die('No direct script access.');
    
    class Request extends Kohana_Request {
        /**
         * Main request singleton instance. If no URI is provided, the URI will
         * be automatically detected using PATH_INFO, REQUEST_URI, or PHP_SELF.
         *
         * @param   string   URI of the request
         * @return  Request
         */
        public static function factory( $uri = TRUE,$client_params = array(), $allow_external = TRUE, $injected_routes = array())
        {
    
            $instance = parent::factory($uri);
    
            $index_page     = Kohana::$index_file;
            $siteconfig     = Model_Siteconfig::load();
            $lang_uri_abbr  = $siteconfig['lang_uri_abbr'];
            $default_lang   = $siteconfig['language_abbr'];
            $lang_ignore    = $siteconfig['lang_ignore'];
    
            $ignore_urls    = $siteconfig['ignore_urls'];
    
            /* get the lang_abbr from uri segments */
            $segments = explode('/',$instance->detect_uri());
    
            $uri_detection  = array_intersect($segments, $ignore_urls);
    
            if(empty($uri_detection))
            {
    
                $lang_abbr = isset($segments[1]) ? $segments[1]:'';
    
                /* get current language */
                $cur_lang = $instance->param('lang',$default_lang);
    
                /* check for invalid abbreviation */
                if( ! isset($lang_uri_abbr[$lang_abbr]))
                {       
                    /* check for abbreviation to be ignored */
                    if ($cur_lang != $lang_ignore) {
                        /* check and set the default uri identifier */
                        $index_page .= empty($index_page) ? $default_lang : "/$default_lang";
    
                        /* redirect after inserting language id */
                        header('Location: '.URL::base().$index_page . $instance->detect_uri());
                        die();
                    }
                }
            }
    
            return $instance;
    
        }
    }
    

    I use "siteconfig" array with language definitions:

    array(
            'language_abbr'     => 'cs',
            'lang_uri_abbr'     => array("cs" => "česky", "en" => "english"),
            'lang_ignore'       => 'it', 
    )
    

    3) Extend/redefine "redirect" method in Controller class for automatic language adding:

    <?php defined('SYSPATH') or die('No direct script access.');
    
    class Controller extends Kohana_Controller {
    
        /**
         * Issues a HTTP redirect.
         *
         * Proxies to the [HTTP::redirect] method.
         *
         * @param  string  $uri   URI to redirect to
         * @param  int     $code  HTTP Status code to use for the redirect
         * @throws HTTP_Exception
         */
        public static function redirect($uri = '', $code = 302)
        {
            $lng = Request::current()->param('lang');
            return HTTP::redirect( (string) '/'.$lng.$uri, $code);
        }
    }
    

    If You would use HTML class (for templates for example), you should probably redefine some other methods like "anchor" for creating anchors with automatic language adding:

    <?php defined('SYSPATH') OR die('No direct script access.');
    
    class HTML extends Kohana_HTML {
    
        /**
         * Create HTML link anchors. Note that the title is not escaped, to allow
         * HTML elements within links (images, etc).
         *
         *     echo HTML::anchor('/user/profile', 'My Profile');
         *
         * @param   string  $uri        URL or URI string
         * @param   string  $title      link text
         * @param   array   $attributes HTML anchor attributes
         * @param   mixed   $protocol   protocol to pass to URL::base()
         * @param   boolean $index      include the index page
         * @return  string
         * @uses    URL::base
         * @uses    URL::site
         * @uses    HTML::attributes
         */
        public static function anchor($uri, $title = NULL, array $attributes = NULL, $protocol = NULL, $index = FALSE)
        {
    
            //default language
            $lng = Request::current()->param('lang');
    
            if ($title === NULL)
            {
                // Use the URI as the title
                $title = $uri;
            }
    
            if ($uri === '')
            {
                // Only use the base URL
                $uri = URL::base($protocol, $index).$lng;
            }
            else
            {
                if (strpos($uri, '://') !== FALSE)
                {
                    if (HTML::$windowed_urls === TRUE AND empty($attributes['target']))
                    {
                        // Make the link open in a new window
                        $attributes['target'] = '_blank';
                    }
                }
                elseif ($uri[0] !== '#')
                {
                    // Make the URI absolute for non-id anchors
                    $uri = URL::site($lng.$uri, $protocol, $index);
                }
            }
    
            // Add the sanitized link to the attributes
            $attributes['href'] = $uri;
    
            return '<a'.HTML::attributes($attributes).'>'.$title.'</a>';
        }
    
    }