Question

I am trying to come up with an efficient way to implement language selection in my site.

I have some flags at the top right which when clicked I want all the text to change into the selected language, where the translations are stored in my database.

Should I do this with a parameter in the url like:

www.myside.com?lang=3

The only issue I have with this, is that it might things complicated as far as the way I route urls and it doesn't make the url look clean either.

Would a better way, be to have it stored in a session and the translations are only fetched from the database when the language is changed. The translations would be kept in a session array, so users don't hit the database on every page load if you know what I mean.

I was wondering if something like the following would be a good way of achieving what I want:

    Session::set('langarray', array(
        'id' => $languageId,
        'cake' => $this->model->getLanguagesNavigation('cake', $languageId),
        'login' => $this->model->getLanguagesNavigation('login', $languageId),
        'register' => $this->model->getLanguagesNavigation('register', $languageId),
        'share' => $this->model->getLanguagesNavigation('share', $languageId),
        'galleries' => $this->model->getLanguagesNavigation('galleries', $languageId),
        'decorator' => $this->model->getLanguagesNavigation('decorator', $languageId),
        'find' => $this->model->getLanguagesContent('find', $languageId),
        'headertext' => $this->model->getLanguagesContent('headerText', $languageId),
    ));

    header('Location: ' . $_SERVER['HTTP_REFERER']);

and in my view:

...
public function render($viewFile, $data = NULL) {
    if(!Session::get('langarray'))
    {
        $this->Language = new Language;
        $this->Language->setLanguage(1);
    }
    if (is_array($data)) {
        extract($data);
    }
    include Vs . $viewFile . '.php';
}
...

Which is simply set the language to 1 (English) if the session var hasn't been set i.e. a language hasn't been picked.

In my HTML I would just echo the corresponding element in the array to get the word:

...
<p><?PHP echo $_SESSION['langarray']['headertext'];?></p>
...

Is this a good method? Or is there a standard way of implementing languages into a site?


My old site currently uses an url method like the one I mentioned (?lang=3) and the foreign variants do quite well in the SEs. I like the idea of using subdomains, but how would I get it to display the correct content on my pages based on whatever come before the first . in the url? E.g. fr. de. etc

Was it helpful?

Solution 3

As I mentioned in my comment above, I would recommend putting the language in the URL mainly for search engine optimization. Admittedly, it can take a bit more work to set up, but I feel the benefits outweigh the cost.

For example, I have a hotel website with English, Spanish, Chinese and French. The URL structure is like this:

/    <- Main page in English
/es/ <- Main page in Spanish
/zh/ <- Main page in Chinese
/fr/ <- Main page in French

Then for sub-pages I do similarly:

/pagename/
/es/pagename/
/zh/pagename/
/fr/pagename/

Then, this is how I redirect the other languages to the correct scripts:

# Spanish
RewriteRule ^es/(.*/)?$ $1/index.php?lang=es [NC,L]

# French
RewriteRule ^fr/(.*/)?$ $1/index.php?lang=fr [NC,L]

# Chinese
RewriteRule ^zh/(.*/)?$ $1/index.php?lang=zh [NC,L]

This works for rewriting the index.php. For other things, I specify them explicitly, usually using a "friendly" URL. For example the "thank you" page for our Contact Us page:

# Contact Us thank you page
RewriteRule ^([a-z_]+)?/?contact/thankyou$ /contact/thankyou.php?lang=$1 [L]

I also used to do the following to rewrite URLs that contained parameters, but I think doing it like this might be deprecated, not too sure (I have it in the code, but since I don't use parameters, it doesn't get triggered):

RewriteCond %{query_string} ([^=]*)=(.*)
RewriteRule ^es/(.*)$ $1/index.php?lang=es&%1=%2 [NC,L]

However, the hotel offers tours and we have a main /tours/ page and I wanted to have a friendly URL for each of the individual tours, like /tours/56/waterfall-hike (with the tour ID and a slug from the tour name), so this handles the rewriting of the tours:

# Rewrite tours
RewriteRule ^([a-z_]+)?/?tours/([0-9]+)/reserve$ /tours/tour_reserve.php?lang=$1&id=$2 [L]
RewriteRule ^([a-z_]+)?/?tours/([0-9]+)/(.*) /tours/tour_text.php?lang=$1&id=$2&urlstr=$3 [L]

# Tours thank you page
RewriteRule ^([a-z_]+)?/?tours/thankyou$ /tours/thankyou.php?lang=$1 [L]

I just need to verify with PHP that the slug string provided is correct and if not do a 301 redirect to the correct URL based on the ID. I use this to calculate it:

function getTourURL($tour_name) {
    // Transliterate non-ascii characters to ascii
    $str = trim(strtolower($tour_name));
    $str = iconv('UTF-8', 'ASCII//TRANSLIT', $str);

    // Do other search and replace
    $searches = array(' ', '&', '/');
    $replaces = array('-', 'and', '-');
    $str = str_replace($searches, $replaces, $str);

    // Make sure we don't have more than one dash together
    $str = preg_replace("/(-{2,})/", "-", $str );

    // Remove all invalid characters
    $str = preg_replace("/[^A-Za-z0-9-]/", "", $str );

    // Done!
    return $str;
}

Then the only other difficult thing is switching languages without just redirecting them back to the home page for that language (yuck!). This is how I did it:

// First define the languages used:
$langs = array(
    'en' => array(
        'lang_code' => 'en_US',
        'locale' => 'en_US.UTF-8',
        'base_url' => '/',
        'name' => 'English',
    ),
    'es' => array(
        'lang_code' => 'es_MX',
        'locale' => 'es_MX.UTF-8',
        'base_url' => '/es/',
        'name' => 'Español',
    ),
    'fr' => array(
        'lang_code' => 'fr_FR',
        'locale' => 'fr_FR.UTF-8',
        'base_url' => '/fr/',
        'name' => 'Français',
    ),
    'zh' => array(
        'lang_code' => 'zh_CN',
        'locale' => 'zh_CN.UTF-8',
        'base_url' => '/zh/',
        'name' => '中国的',
    ),
);
define('LOCALE', $_GET['lang']);

// Then get the path to the current script after the language code
$path = (LOCALE == 'en') ? '' : LOCALE.'/';

$parsed_url = parse_url($_SERVER['REQUEST_URI']);
$path = ltrim(str_replace('/'.LOCALE , '', $parsed_url['path']), '/');

define('REDIRECT_SCRIPT', $path);

// Then I put all the links into an array to be displayed in the menu
foreach ($langs as $lang => $arr) {
    if ($lang == LOCALE) {
        continue;
    }
    $link = (isset($lang_override[$lang]))
        ? $lang_override[$lang]
        : $arr['base_url'] . REDIRECT_SCRIPT;
    $lang_subs[] = array(
        'name' => '<div class="'.$lang.'"></div> '.$langs[$lang]['name'],
        'link' => $link,
        'lang' => $lang,
    );
}

This probably won't work for you out of the box, but should at least give you a starting point. Try a print_r($lang_subs); to see what it contains and adapt it to your site's design.

OTHER TIPS

Maybe I'm old fashioned but I've always had a lang folder with files for each languages (lang.en.php, lang.fr.php, lang.es.php, and so on).

In each file I've got an array, like this one:

$langarray = array("login" => "...", "connect" => "...", "logout" => "...");

Eventually with real stuff in them... works better :}

And then, depending on the $_SESSION variable, I include the right file. You can even stock "en" and include lang.'.$_SESSION['lang'].'.php.

It seems slightly better not having to query SQL for that kind of thing but less easy to maintain. I think this is the type of problem where nobody's wrong.

Yes, saving the language code in the session is better than constantly passing around a parameter.

No, storing the translated text in the session doesn't make sense because then you are storing the same text over and over in memory per user. Better to implement database caching or have a PHP file to include for the translation table than to store it in the session.

Instead of making up numeric codes for languages, you really should use the standard letter abbreviations that are part of the HTML spec. Browsers send preferred languages in order of preference as a header called Accept-Language. To avoid making the user click a language choice, you could read that list from the header and iterate through it until you find the first language you support. But always good to give the user some manual way to change it.

Zend framework has some functions for dealing with languages but I've never used it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top