0

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

imperium2335
  • 23,402
  • 38
  • 111
  • 190
  • 3
    For search engine optimization, I would recommend putting the language in the URL. Search engines typically don't use sessions while browsing your site, so you could potentially be missing out on a lot of indexed pages. You can do this either by having a separate sub-domain for each language or a "sub-folder" style. e.g. Main page is example.com/page/ which defaults to English, then the Spanish equivalent would be example.com/es/page/. This is what I've done with my hotel's website all using .htaccess. – Mike Jan 23 '14 at 23:33
  • You should really use poedit. http://stackoverflow.com/questions/11563403/poedit-and-php-annotations#11625690 – pregmatch Jan 23 '14 at 23:40
  • @Mike Would you be willing to share the part of your .htaccess that does that? My main concern is how it may not work because of how I route requests (www.site.com/controller/method/param1...). – imperium2335 Jan 24 '14 at 11:10
  • @imperium2335 I'm a bit slow (been busy lately), but I just posted an answer. Hopefully it helps. – Mike Feb 13 '14 at 03:49

3 Answers3

1

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.

mombul
  • 327
  • 1
  • 10
1

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.

developerwjk
  • 8,619
  • 2
  • 17
  • 33
  • 1
    How does Google-bot get to your other languages' pages if your site returns English and it requires sessions to get to other languages? – Mike Jan 23 '14 at 23:43
  • Plus one, because this is how Facebook does it via sessions. – Justin E Jan 23 '14 at 23:45
  • You make a good point about SEO, Mike. But the two can be used together. You can include the language in the URL as you suggest, and also keep it in the session. That way if later I go just to the domain, it remembers the language I already chose and doesn't make me choose again. – developerwjk Jan 23 '14 at 23:48
0

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.

Mike
  • 23,542
  • 14
  • 76
  • 87
  • Thanks! I have done something similar to what you suggested, instead using subdomains like fr.mysite.com etc. Just personal preference I guess but works a similar way. – imperium2335 Feb 13 '14 at 12:16