URI localization: Translating the uri-segments

#1
[eluser]Go-Online[/eluser]
Hi,

I'm working on a website that has to be presented in at least 3 languages (probably 4). Therefor I'd like to use good looking URI's (www.example.com/en/controller_in_right_lang).
For example a page about tools would be /en/tools in English, but in Dutch is should be /nl/Gereedschappen . The language thing (nl, en, ...) is already handled, bt I'm looking for the last part to translate ...

Does anyone have an idea how to solve this?

#2
[eluser]rogierb[/eluser]
You can do this using routes or in the .htaccess. I guess routes is more easy to set up and maintain.

Code:
$route['en/tools'] = 'tools';
$route['en/tools/(.+)'] = 'tools/$1';
$route['nl/gereedschappen'] = 'tools';
$route['nl/gereedschappen/(.+)'] = 'tools/$1';

Or are you talking about how to automatically create an anchor in different languages?

#3
[eluser]Go-Online[/eluser]
Hi,

Thanks for the reply, but it has to be, as you thought, be autmotically ...
When the site admin make a new page in the different languages, or there is a new language, there may be no scripting needed anymore ...

#4
[eluser]rogierb[/eluser]
Then I would go for a pre-controller hook that rewrites the uri segments in the languages that is selected.

#5
[eluser]Go-Online[/eluser]
Hi,

Do you have a lead on how to write a pre-controller hook?
Something on the wiki or so?

#6
[eluser]rogierb[/eluser]
Check http://codeigniter.com/wiki/I_want_to_ta...-_rogierb/
for an example of a pre-system hook.

There is information about hooks in the user guide aswell

Just get hooks working and a pre-controller hook that echoes a word and go from there

#7
[eluser]Fabdrol[/eluser]
I don't think you need to go through all that trouble creating a hook..
Personally I'd do something like this:

Routes config:
Code:
// reroute to controller 'tomtom', method 'map', with arguments $1 and $2.
  $route['(:any)/(:any)'] = 'tomtom/map/$1/$1';

Tomtom.php controller
Code:
class Tomtom extends Controller {
    
    function __construct() {
      parent::Controller();
      $this->load->library('database');
    }

    function map($lang, $method) {
      $this->db->where('lang', $lang);
      $get = $this->db->get('local_methods');
      
      if($get->num_rows() <= 0) {
        // this lang is not known. throw error!
        log_message('error', 'language not found, redirecting to default language');

        // map to the global controller, doing the real action.
      } else {
        // language found. continue
        $language = $get->row();
        if($language->{$method} !== false) {
          // the method exists for this language. map to the 'real' method.
        }
      }
    }

  }

In short, what your code does..
1. You send an url like: "nl/gereedschappen/" to the system.
2. The Router maps that url to the language handler controller.
3. The TomTom controller checks the db if the language exists, and if so, if the method exists.
4. The TomTom controller takes the 'real' data handling method and controller to which the localized controller should point from the database and sends the user through that controller
5. Be sure not to use redirect(), since it'll change the url!!

Any questions, or want more code examples? Drop me a line at fabian [at] dotbrilliance [dot] nl

succes!
Fabian

#8
[eluser]Nalorin[/eluser]
Fabdrol:

Your solution seems interesting as I'm currently working on localization for a project to get information from the database based on where the user is at.

My database tables will have a url-style location for filtering(eg. "buffalo.ny.usa" or "toronto.on.ca"). There are two ways that I've been considering implementing localization:

1) Using subdomains. So any subdomain would be remapped to the main site, and the subdomain would be parsed, cleaned and used to filter by city. And every visitor will be required to select their location. So,

Code:
chicago.mysite.com/category/product/id

becomes

Code:
www.mysite.com/category/product/id
// with filter applied:
"WHERE location like 'chicago.il%'"

OR

2) Using the URI method below, the result would be the same as above.

Code:
www.mysite.com/chicago/category/product/id

---

The problem with #1 is that my current hosting solution doesn't support wildcard subdomains, so I can't easily localize by city like that. (If I start spending more money on hosting, then it will support it). Also, my current home internet setup (which I am not in control of) makes it difficult to setup a proper test environment for developing this solution for production.

The problem with #2 is that I don't know how to do it... I'd really like to just pull the city out, store it in a variable, and do the equivalent of an internal redirect to end up with the result in the second code block above. I don't want to have to worry about the order of segments when users start filtering data by price, condition, etc.

Do you have any suggestions?

#9
[eluser]Fabdrol[/eluser]
Hi Nalorin,

Well, you could use my solution, but I recon it'll be useless when you have a variable amount of parameters.
Here's an update for it:

In config/routes.php
Code:
// replace the dots by the number of variables you'll need, until $n
// parameter one is always the city, two always the controller, three the method. $4 to $n are the max number of parameters
$route['(:any)/(:any)/(:any)/.../(:any)'] = "reroute/to/$1/$2/$3/.../$n";

Create a controller: controllers/reroute.php
Code:
&lt;?php if(!defined('BASEPATH')) exit('No direct script access allowed!');

class Reroute extends Controller {

    public function __construct() {
        parent::__construct();
        
        $this->load->helper('url');
    }
    
    public function to() {
        $args = func_get_args();
        $city = $args[0];
        $uri = '';

        // set the city in a session.
        $this->session->set_userdata('city', $city);

        for($i = 1; $i < count($args); $i += 1) {
            $uri .= $args[$i] . '/';
        }

        redirect($uri);
    }

}

The reroute class' to() method fetches the arguments passed to the method, caches the first parameter as the city, and parses the rest into a redirect url (to another class, method and parameters)

Example:
Code:
User requests:
www.mysite.com/chicago/category/product/876/pictures/

The route routes this request to the to() method of the reroute class, and this method fetches an array containing:
[0] => chicago,
[1] => category,
[2] => product,
[3] => 876,
[4] => pictures

The to() method sets a session containing the city, and parses a redirect url:
redirect('category/product/876/pictures');

#10
[eluser]Nalorin[/eluser]
Thanks for your response, Fabdrol.

Your code looks like it will do the work I need, but may do one thing that is undesirable - redirect the user's browser. I was hoping to have this function transparently, similar to an internal redirect using rewriting.

Here's what I was hoping to accomplish, assuming a URL of www.mysite.com/chicago/fruit/pear/123

Left column is the URI shown in the user's browser. Right column is the URI the server is working with.

Code:
1) '/chicago/fruit/pear/123'    '/chicago/fruit/pear/123'
2) '/chicago/fruit/pear/123'    '/fruit/pear/123'
3) '/chicago/fruit/pear/123'    ''// Output sent. Apache thread terminates
Step 1: Server receives URI request from browser
Step 2: Server parses URI and extracts city, then continues executing category controller
Step 3: Script execution completes, thread is destroyed, server waits to receive new request

This way, if the user doesn't find what they want in chicago, they can simply change the city to milwaukee to see if what they're looking for is there:
Code:
'www.mysite.com/milwaukee/fruit/pear/123'
and the page is loaded with the new city's results

Is it better (or even possible) to grab the city from the URL as a hook or something, store it as a variable, and then load that variable (eg. $city) from the controller's constructor? Or, is it possible to adapt your method to have it function like this?


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2020 MyBB Group.