Post Reply 
 
Thread Rating:
  • 0 Votes - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
A true multilingual website in under Prestashop
01-04-2010, 01:49 AM
Post: #1
A true multilingual website in under Prestashop
I found this French tutorial at http://www.vemeo.fr/blog/ecommerce/prest...ltilingue/ site. So I translated it to English also.

If you follow this blog regularly you know we very rarely talk about development, code, PHP, MySql etc ...
For once we'll make an exception by making a tutorial that lets you turn into a real shop Prestashop multilingual.
For we must not fool ourselves Prestashop claims that its solution is multilingual, which is perfectly true at the user level but wrong in referencing (even for version 1.2.3). Here is a method optimized for Prestashop 1.1 but I think it works for version 1.2.3.

Preamble
To manage the change of language, Prestashop uses cookies. Simply put, when you arrive on site Prestashop in French, the website stores the value "French" of the cookie and when you click a flag to change language of the site changes the cookie value. Problem: Search engines are unable to store cookies ...
The result is that your visitors can "switch" languages without problems, but Goolgle indexing your site with the default language.

For example, for a client we had the following problem:
The site was bilingual (French / Spanish) and the default language was French. We therefore for the same product 2 pages 2 URL (1 per language):
http://www.mon-site.com/01-mon-produit.html (for French)
http://www.mon-site.com/01-mi-producto.html (Spanish)

But Google can not store cookies, was unable to see content in a language other than the default language.
Indeed, the code Prestashop is made so that if you can not store cookies, you will be back on the default language (I'm simplifying).
Results for two URLs to our site we content in French (default).
You can imagine the problems: poorly Google.es indexing pages (since nothing was in Spanish except the URL), the Spanish visitors arriving by Google.es had a content in French, and we had a big duplicate content!

A site two URLs ...
The only solution we found was to force the default language by URL (the area more precisely). For this, we first created the subdomain es.mon-site.com, which points to the same directory as http://www.my-site.com.
NB: We do not normally try but it also works with another domain (eg http://www.my-site.es)

For example: if the field is http://www.my-site.com, we force the French, and if the field is es.mon-site.com, we force the Spanish.

To do this, we must go into the classes folder and open the file Tools.php
Around line 112, change the code like this (a big thank you to Julian Breux):
PHP Code:
/* Automatically detect language if not already defined */
if ( isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
{
$array split(','Tools::strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']));
 
// It forces the language by field
if($_SERVER['HTTP_HOST'] == 'www.mon-site.com'// FR
{
$array[0] = 'fr';
 
}
if(
$_SERVER['HTTP_HOST'] == 'es.mon-site.com'// ES
{
$array[0] = 'es';
 

Warning! If you want to use the multilingual mode on your admin, you must specify that it should be applied only on the public part of your site. For this, we will verify that the URL is not that the admin.
Then use this code instead of the previous:
PHP Code:
/* Automatically detect language if not already defined */
 
// Check if you are in the admin or not
if(ereg('admin'$_SERVER['REQUEST_URI']))
/* Above replace 'admin' with the directory of your admin
For example if the url to access your admin is www.mon-site.com/admin-boutique/
Rempalcer 'admin' to 'admin-shop'
*/
$admin 1;
 
if ( isset(
$_SERVER['HTTP_ACCEPT_LANGUAGE']) AND $admin != 1)
{
$array split(','Tools::strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']));
 
// It forces the language by field
if($_SERVER['HTTP_HOST'] == 'www.mon-site.com'// FR
{
$array[0] = 'fr';
 
}
if(
$_SERVER['HTTP_HOST'] == 'es.mon-site.com'// ES
{
$array[0] = 'es';
 

At this point you are already well advanced. Now we must make a small configuration that will cause the engines to index the URL property of the 2 languages.
To do this, go to your classes and modify the file as Configuratrion.php below (thank you to Cédric Girard):

Around line 99
PHP Code:
elseif (key_exists($keyself::$_CONF))
 {
 
// MODIFICATION LANGUE PAR DEFAUT POUR LES ROBOTS
 
if($key=='PS_LANG_DEFAULT')
 {
 
// Variable langue => on verifie le domaine et on force la langue
 
if($_SERVER['HTTP_HOST'] == 'www.mon-site.com'// FR
 
{
 return 
'2'// L'id du français
 
}
 if(
$_SERVER['HTTP_HOST'] == 'es.mon-site.com'// ES
 
{
 return 
'5'// L'id de l'espagnol
 
}
 
 }
 else
 {
 return 
self::$_CONF[$key];
 }
 
// FIN DE MODIFICATION
 

NB: For the id of your language, simply go to your admin, click the Tools tab and then under the tab "Languages" and there you will have the id of your language.

Now that everything is optimized for search engines must re-optimized the site for the visitor.

For this, we must modify the module blocklanguages. In the Modules folder, then blocklanguages folder, edit the file blocklanguages.tpl like below:
To line 3
PHP Code:
<ul id="first-languages">
 {foreach 
from=$languages key=k item=language name="languages"}
 <
li {if $language.iso_code == $lang_iso}class="selected_language"{/if}>
 {if 
$language.iso_code != $lang_iso}
<!--
On modifie les url selon le code iso de la langue -->
<
a href="{if $language.iso_code == 'es'}http://es.mon-site.com{/if}{if $language.iso_code == 'fr'}http://www.mon-site.com{/if}" title="{$language.name}">{/if}
 <
img src="{$img_lang_dir}{$language.id_lang}.jpg" alt="{$language.name}" />
 {if 
$language.iso_code != $lang_iso}</a>{/if}
 </
li>
 {/foreach}
 </
ul
NB: For the iso code of your language, simply go to the same place as the id.
Note 2: With this change, you must pass by the home every time you change language. It's annoying but you can not do otherwise.

If you use a subdomain and only if you use a subdomain, you must configure it in the admin area of your shop. To do this go to your admin, click the Tools tab and then under the tab "Subdomains". Then just click again and add your subdomain (in this case "es").

At this level, and if you have any monitoring well, all will work.

Now if you want to use a sitemap, make the changes below.

We still have a problem with the sitemap, it will therefore be necessary to optimize the module gsitmap. I confess that we have not had time too look into this module and it is very poorly optimized but it works ...

Then you head to the modules folder, then gsitemap and edit the file gsitemap.php.

From the line about 47, you must modify the code as follows:
PHP Code:
/// Modifications multilingue
 
private function _postProcess()
 {
 
 
// On génére le fichier français
 
$link = new Link();
 
$fp fopen($this->_filename'w');
 
$xml = new SimpleXMLElement('<urlset xmlns=&quot;http://www.google.com/schemas/sitemap/0.84&quot;></urlset>');
 
 
// Catégories françaises
 
$categories Db::getInstance()->ExecuteS('
 SELECT c.id_category, c.level_depth, link_rewrite, DATE_FORMAT(date_add, \'%Y-%m-%d\') AS date_add, cl.id_lang
 FROM '
._DB_PREFIX_.'category c
 LEFT JOIN '
._DB_PREFIX_.'category_lang cl ON c.id_category = cl.id_category
 LEFT JOIN '
._DB_PREFIX_.'lang l ON cl.id_lang = l.id_lang
 WHERE l.`active` = 1 AND cl.`id_lang` = 2'
);
// Ci dessus mettre l'id de votre 1ere langue dans `id_lang` = 2
foreach($categories as $category)
 {
 if ((
$priority 0.9 - ($category['level_depth'] / 10)) < 0.1)
 
$priority 0.1;
 
$sitemap $xml->addChild('url');
 
// On définie les urls des catégories françaises. Mettre le domaine définie pour la langue française
 
$sitemap->addChild('loc','http://www.mon-site.com'.htmlspecialchars($link->getCategoryLink($category['id_category'], $category['link_rewrite'])));
 
$sitemap->addChild('priority'$priority);
 
$sitemap->addChild('lastmod'$category['date_add']);
 
$sitemap->addChild('changefreq''monthly');
 }
 
 
// Produit français
 
$products Db::getInstance()->ExecuteS('
 SELECT p.id_product, pl.link_rewrite, DATE_FORMAT(date_add, \'%Y-%m-%d\') AS date_add, pl.id_lang, cl.`link_rewrite` AS category, (
 
 SELECT MIN(level_depth)
 FROM '
._DB_PREFIX_.'product p2
 LEFT JOIN '
._DB_PREFIX_.'category_product cp2 ON p2.id_product = cp2.id_product
 LEFT JOIN '
._DB_PREFIX_.'category c2 ON cp2.id_category = c2.id_category
 WHERE p2.id_product = p.id_product) AS level_depth
 FROM '
._DB_PREFIX_.'product p
 LEFT JOIN '
._DB_PREFIX_.'product_lang pl ON p.id_product = pl.id_product
 LEFT JOIN `'
._DB_PREFIX_.'category_lang` cl ON (p.`id_category_default` = cl.`id_category` AND pl.`id_lang` = cl.`id_lang`)
 LEFT JOIN '
._DB_PREFIX_.'lang l ON cl.id_lang = l.id_lang
 WHERE l.`active` = 1 AND pl.`id_lang` = 2' 
);
// Ci dessus mettre l'id de votre 1ere langue dans `id_lang` = 2
 
foreach($products as $product)
 {
 if ((
$priority 0.7 - ($product['level_depth'] / 10)) < 0.1)
 
$priority 0.1;
 
$sitemap $xml->addChild('url');
// On définie les urls des produit français. Mettre le domaine définie pour la langue française
 
$sitemap->addChild('loc''http://www.mon-site.com'.htmlspecialchars($link->getProductLink($product['id_product'], $product['link_rewrite'], $product['category'])));
 
 
$sitemap->addChild('priority'$priority);
 
$sitemap->addChild('lastmod'$product['date_add']);
 
$sitemap->addChild('changefreq''weekly');
 }
 
 
$xmlString $xml->asXML();
 
fwrite($fp$xmlStringTools::strlen($xmlString));
 
fclose($fp);
 
 
$res file_exists($this->_filename);
 
 
$this->_html .= '<h3 style=&quot;margin-bottom: 20px&quot;>';
 
$this->_html .= $res $this->l('Sitemap file successfully generated') : $this->l('Error while creating sitemap file');
 
$this->_html .= '</h3>';
 
 
// On génére le fichier de la 2eme langue
 
$link_es = new Link();
 
$fp_es fopen($this->_filename_es'w');
 
$xml = new SimpleXMLElement('<urlset xmlns=&quot;http://www.google.com/schemas/sitemap/0.84&quot;></urlset>');
 
 
// Catégories de la 2eme langue
 
$categories Db::getInstance()->ExecuteS('
 SELECT c.id_category, c.level_depth, link_rewrite, DATE_FORMAT(date_add, \'%Y-%m-%d\') AS date_add, cl.id_lang
 FROM '
._DB_PREFIX_.'category c
 LEFT JOIN '
._DB_PREFIX_.'category_lang cl ON c.id_category = cl.id_category
 LEFT JOIN '
._DB_PREFIX_.'lang l ON cl.id_lang = l.id_lang
 WHERE l.`active` = 1 AND cl.`id_lang` = 5'
);
// Ci dessus mettre l'id de votre 2eme langue dans `id_lang` = 5
foreach($categories as $category) {
 if ((
$priority 0.9 - ($category['level_depth'] / 10)) < 0.1)
 
$priority 0.1;
 
$sitemap $xml->addChild('url');
 
// On définie les urls des catégories de la 2eme langue. Mettre le domaine définie pour la 2eme langue
 
$sitemap->addChild('loc','http://es.mon-site.com'.htmlspecialchars($link->getCategoryLink($category['id_category'], $category['link_rewrite'])));
 
$sitemap->addChild('priority'$priority);
 
$sitemap->addChild('lastmod'$category['date_add']);
 
$sitemap->addChild('changefreq''monthly');
 }
 
 
$products Db::getInstance()->ExecuteS('
 SELECT p.id_product, pl.link_rewrite, DATE_FORMAT(date_add, \'%Y-%m-%d\') AS date_add, pl.id_lang, cl.`link_rewrite` AS category, (
 SELECT MIN(level_depth)
 FROM '
._DB_PREFIX_.'product p2
 LEFT JOIN '
._DB_PREFIX_.'category_product cp2 ON p2.id_product = cp2.id_product
 LEFT JOIN '
._DB_PREFIX_.'category c2 ON cp2.id_category = c2.id_category
 WHERE p2.id_product = p.id_product) AS level_depth
 FROM '
._DB_PREFIX_.'product p
 LEFT JOIN '
._DB_PREFIX_.'product_lang pl ON p.id_product = pl.id_product
 LEFT JOIN `'
._DB_PREFIX_.'category_lang` cl ON (p.`id_category_default` = cl.`id_category` AND pl.`id_lang` = cl.`id_lang`)
 LEFT JOIN '
._DB_PREFIX_.'lang l ON cl.id_lang = l.id_lang
 WHERE l.`active` = 1 AND pl.`id_lang` = 5'
);
// Ci dessus mettre l'id de votre 2eme langue dans `id_lang` = 5
foreach($products as $product)
 {
 if ((
$priority 0.7 - ($product['level_depth'] / 10)) < 0.1)
 
$priority 0.1;
 
$sitemap $xml->addChild('url');
 
// On définie les urls des produits de la 2eme langue. Mettre le domaine définit pour votre 2eme langue
 
$sitemap->addChild('loc''http://es.mon-site.com'.htmlspecialchars($link->getProductLink($product['id_product'], $product['link_rewrite'], $product['category'])));
 
 
$sitemap->addChild('priority'$priority);
 
$sitemap->addChild('lastmod'$product['date_add']);
 
$sitemap->addChild('changefreq''weekly');
 }
 
 
$xmlString_es $xml->asXML();
 
fwrite($fp_es$xmlString_esTools::strlen($xmlString_es));
 
fclose($fp_es);
 
 
$res_es file_exists($this->_filename_es);
 
 
$this->_html .= '<h3 style=&quot;margin-bottom: 20px&quot;>';
 
$this->_html .= $res_es $this->l('Sitemap file successfully generated') : $this->l('Error while creating sitemap file');
 
$this->_html .= '</h3>';
 
 }
//// Fin modif 
With this technique, you will have 2 sitemaps (1 per language). One called sitemap.xml and the other sitemap_es.xml. If you feel the change of names you can.
You need 2 for Google Sitemaps does not accept URLs from 2 different areas in the same sitemap. Do not forget to post the two sitemaps on your account "tool for webmasters.

That is a bit complicated but so far it is the only solution we have found a real site Prestashop in multiple languages.

If you have any questions please. Do not hesitate to give your further information.
Find all posts by this user
Quote this message in a reply
Thank given by iboMonkey
06-14-2010, 09:09 AM
Post: #2
RE: A true multilingual website in under Prestashop
Hello,

I'm absolutely a scripting-noob, so maybe these questions are rediculous (with other people it seems to work fine...) But, I get blank pages when applying the script modifications.

I've tried first with Tools.php and Configuration.php, maybe I don't even know wether to just write the new code somewhere in between or to replace other pieces of code with this.

My idea is to change:
Quote:/* Automatically detect language if not already defined */
if (!$cookie->id_lang AND isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
{
$array = explode(',', Tools::strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']));
if (Validate::isLanguageIsoCode($array[0]))
{
$lang = new Language(intval(Language::getIdByIso(strval($array[0]))));
if (Validate::isLoadedObject($lang) AND $lang->active)
$cookie->id_lang = intval($lang->id);
}
}

With the suggestion for the modification around line 112 in Tools.php. Is that correct?

After reply, I will take the next step in modifying these files Smile

Thanks in advance,
iboMonkey
Find all posts by this user
Quote this message in a reply
07-12-2010, 05:00 PM
Post: #3
JR Split File 1.2
Want to be equipped? Visit - JR Split File 1.2
Find all posts by this user
Quote this message in a reply
Post Reply 


Forum Jump: