Damien Mathieu

Blog d’un développeur web

SQL : créer un nouvel uplet si la requête ne retourne aucun résultat

octobre22

Supposons le contexte suivant : vous avez une application traduite en plusieurs langues.
Pour chacune des langues, vous avez une ou plusieurs chaines de caractères. Et dans votre application, vous faites, par exemple :

__(’maChaine’);

Ainsi, la chaine appropriée est affichée en fonction de la langue que vous avez sélectionnée.
Suite à cela, vous avez une base de données qui contient chacune de vos chaines avec la langue et la valeur dans cette même langue.

Lorsque vous appellez la fonction __() avec la valeur de votre choix, vous faites donc un appel à votre base de données qui vous retourne la valeur de la chaine pour la langue en cours.

Le problème, c’est que lorsque vous développez votre application, vous ne pensez pas toujours à ajouter la chaine à chaque fois que vous la placez dans votre code source. Cela serait un tantinet lourd.

La procédure stockée suivante vous permet dont de faire la requête de selection adéquate en fonction de la chaine de caractères et de la langue.
Et si il n’y a aucun élément de retourné, elle en ajoutera un dans la base, avec la chaine vide.

Après, vous n’avez plus qu’à remplir toutes les chaines qui ont été ajoutées lorsque vous surfez dans votre application :)

CREATE PROCEDURE getTrads
@chaine varchar(150),
@langue int
AS
BEGIN
SELECT valeur FROM params_langue
WHERE chaine = @chaine
AND id_langue = @langue
IF (@@Rowcount < 1)
INSERT INTO [params_langue] ([chaine], [valeur], [id_langue]) VALUES (@chaine, ”, @langue)
END

Note : cette procédure a été construire pour fonctionner sous SQL Server. Elle n’est pas forcément portable sur tous les SGBDR. Notamment la variable @@Rowcount, qui peut ne pas être disponible partout.

Puis appellez votre procédure stockée :

EXECUTE getTrads
"maChaine", 1

Ou 1 est l’identifiant de votre langue (vous pouvez remplacer cet identifiant par son nom si vous le désirez. Mais je vous le déconseille).

PHP : détecter la langue favorite de l’utilisateur

juillet4

Supposons le cas d’un site multilingue, qu’il soit architecturé en sous-répertoires ou sous-domaines.
Lorsque vous arrivez sur la base du site (/ ou www), aucune langue n’est définie. Et vous n’avez aucun contenu à afficher.

Il vous faut donc rediriger l’utilisateur vers une autre page qui correspondra à la langue qu’il est le plus susceptible de désirer.
De nombreux sites, corporate y compris, ne s’embêtent pas et proposent simplement une liste de liens vers les diverses langues.

Ceci est à ne surtout pas faire. Cela avait notemment été dit par Elie Sloïm lors des ateliers Paris Web de l’an dernier (d’ailleurs les dates du prochain Paris Web ont été divulguées !)
Suite à une discussion sur le forum seosphere, je publie ici le code que j’utilise sur RefStats pour détecter la langue préférée de l’utilisateur et le rediriger vers le répertoire approprié. Si vous utilisez des sous-domaines, il suffit de déplacer /fr en fr.
Note : le code ici est adapté afin d’enleve la dépendance à CakePHP.

$langs = array('en' => array('title' => 'English', 'visible' => 0) , 'fr' => array('title' => 'Français', 'visible' => 1));
$defaultLang = 'fr';

$_d = split (’[,;]‘, $_SERVER['HTTP_ACCEPT_LANGUAGE']);
$f = false;
$selected = null;
foreach($_d as $l) {
if (isset($langs[$l]) && $langs[$l]['visible'] == 1 && $f == false) {
$selected = $l;
$f = true;
}
}
if ($f == false) $selected = $defaultLang;

header(’location: /’.selected, true, 301);
die();

Quelques explications.
Ce code doit être placé sur votre page /index.php. la variable $langs contient toutes les langues disponibles. Ici, j’ai mis un élément ‘nom’ car dans le cas de RefStats, cette variable sert également à mettre le nom de la langue en haut de page.
Le ‘visible’ n’est pas non plus utile ici.

Nous regardons donc le contenu de HTTP_ACCEPT_LANGUAGE, qui contient les langues préférées de l’utilisateur, par ordre de préférence.
On prends la première que l’on connaisse. Si il n’y en a aucune, on prends la valeur de $defaultLang.
Et on redirige vers le répertoire de la langue.

Il est totalement inutile de placer la langue dans la session. En effet, vu que vous serez ensuite dans le répertoire de la langue, vous aurez toujours l’information de celle-ci.
Et si vous placez l’information en session et forcez toujours cette langue, vous courrez le risque d’avoir un utilisateur qui aurait une configuration inappropriée (cela peut arriver lors de vacances à l’étranger par exemple) qui ne pourra pas voir votre site dans sa langue maternelle.

Pour finir, voici le code non modifié pour ceux qui utiliseraient CakePHP.

Dans app_controller.php, avant la déclaration de classe :
uses('L10n');

Dans app_controller.php, en dehors de toute méthode :
var $langs = array('en' => array('title' => 'English', 'id' => 'eng', 'visible' => 0) , 'fr' => array('title' => 'Francais', 'id' => 'fre', 'visible' => 1, 'wp_cat' => 3));
var $defaultLang = 'fr';

Dans app_controller.php, fonction beforeFilter :
if (!isset($this->params['lang']) && !empty($this->params)) {
$_d = split (’[,;]‘, env(’HTTP_ACCEPT_LANGUAGE’));
$f = false;
$selected = null;
foreach($_d as $l) {
if (isset($this->langs[$l]) && $this->langs[$l]['visible'] == 1 && $f == false) {
$selected = $l;
$f = true;
}
}
if ($f == false) $selected = $this->defaultLang;

$this->redirect(’/’.$selected, 301);
die();
} elseif (!empty($this->params['lang']) && isset($this->langs[$this->params['lang']])) {
Configure::write(’Config.language’, $this->langs[$this->params['lang']]['id']);
} elseif (!empty($this->params)) {
$this->cakeError(’error404′, array(array(’action’ => $this->action)));
} else {
$url = env(’argv’);
$url = $url[0];
$url = ‘/’.str_replace(’url=’, ”, $url);

$l = explode(’/', $url);
$l = $l[1];

if (!isset($this->langs[$l]) && Configure::read(’debug’) == 0) {
$this->cakeError(’error404′, array(array(’action’ => $this->action)));
}
}
$this->params['langs'] = $this->langs;

Et enfin dans routes.php, pour permettre l’ajout du paramètre de langue avant le contrôleur et l’action :
Supprimer la ligne suivante :
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
Et ajouter à la place les deux lignes suivantes :
Router::connect('/:lang/', array('controller' => 'pages', 'action' => 'display', 'home'));
Router::connect('/:lang/:controller/:action/*');

Ceci définira la langue dans la configuration de CakePHP, vous permettant par la suite d’utiliser les outils d’internationalisation du framework.

posted under PHP | No Comments »

Rss Feeds

En Français
In English