JeuWeb - Crée ton jeu par navigateur
Stocker du texte hors des vues, les solutions ? - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Stocker du texte hors des vues, les solutions ? (/showthread.php?tid=6683)



Stocker du texte hors des vues, les solutions ? - php_addict - 02-03-2013

Bonjour

suite à http://www.jeuweb.org/showthread.php?tid=9146&pid=117034#pid117034 j'ouvre ce topic:

La question est de savoir comment stocker du texte hors des fichiers vues (MVC) comme par exemple les textes des emails à envoyer.

Une contrainte supplémentaire est qu'il est necessaire d'inclure du code PHP car des portion de textes peuvent être dynamiques.

pour le moment j'ai opté pour le JSON, mais ca devient assez vite illisible:


<?php
header("Content-type:application/json");
header ("Cache-Control: no-cache, must-revalidate");
header ("Content-Type: application / json; charset=UTF-8'");

$array['email_1'] = '<p>';
$array['email_1'] .= 'Bonjour,<br><br>Bienvenue sur ' . URL_DU_JEU. ' <br><br>';
$array['email_1'] .= '</p>';


$array['email_2'] = '<p>';
$array['email_2'] .= 'Salut, ca va?';
$array['email_2'] .= '</p>';

echo(json_encode($array));
?>

ce qui donne

Code :
{"email_1":"<p>Bonjour,<br><br>Bienvenue sur MonSuperJeu.com <br><br><\/p>","email_2":"<p>Salut, ca va?<\/p>"}

et on récupére le texte que l'on veut, par exemple "email_1" avec une function qui va allez chercher l'entrée "email_1" dans le tableau JSON

du coup je me demande si il y a mieux comme façon de faire, xml ou autre...

avez-vous des avis sur la questions?

Merci de m'avoir lu une fois de plus

bonne journée!


RE: Stocker du texte hors des vues, les solutions? - Maks - 02-03-2013

Tu pourrais utiliser <<<EOF et EOF; pour mettre en forme un peu plus proprement ton texte.
Sinon pourquoi ne pas utiliser les templates pour générer des modèles de mails ?


RE: Stocker du texte hors des vues, les solutions? - Sephi-Chan - 02-03-2013

Tu ne le précises pas dans ton sujet, mais je suppose qu'on parle ici de faciliter l'internationalisation.

Je connais et utilise trois solutions selon mes cas d'utilisation :
  • Utiliser un outil d'internationalisation (directement ou via un wrapper) ;
  • Avoir des templates pour chaque langue ;
  • Faire ça uniquement côté Javascript ;

Utiliser un outil d'internationalisation

Mon outil d'internationalisation est Ruby I18n, très bien intégré dans Ruby on Rails. Il permet d'écrire (que ce soit dans les vues, les contrôleurs et les modèles, bien que ces derniers ne devraient pas être concernés) des choses comme :


<!-- Une traduction toute simple. -->
<h1><%= t('title') %></h1>

<div>
<!-- La traduction contient du HTML. -->
<%= t('presentation') %>
</div>

<div>
<!-- On peut aussi traduire des dates. -->
<%= l(Time.now, { format: :long }) %>
</div>

<div>
<!-- On peut interpoler des valeurs dans les traductions. -->
<%= t('user.welcome', { name: current_user.name }) %>
</div>

<div>
<!-- Y compris des dates traduites ! -->
<%= t('user.last_connection', { date: l(current_user.last_connection_at) }) %>
</div>

<div>
<!-- Les pluriels sont bine supportés. -->
<%= t('user.messages_count', { count: messages.count }) %>
</div>

Et les traductions sont stockées (par défaut dans des fichiers YAML, mais on peut utiliser la base de donnée, Redis, etc.) de la forme suivante :


fr:
title: "Seelies"
presentation_html: "Seelies est un <strong>jeu de stratégie communautaire</strong> par navigateur."

date:
formats:
default: "%e %b"
long: "%e %B %Y"

user:
welcome: "Bienvenue ${name}"
last_connection: "Votre dernière connexion remonte au ${date}."
messages_count:
zero: "Vous n'avez aucun nouveau message."
one: "Vous avez un nouveau message."
other: "Vous avez %{count} nouveaux messages."

On a donc des namespaces bien définis et on peut bien sûr les définir dans plusieurs fichiers.

Je vous invite à jeter un œil au dépôt communautaire de traductions, c'est intéressant de voir comment sont stockées toutes les choses un peu spéciales comme les pluriels, les dates et heures, les mécanismes pour générer des phrases comme "Il y a 5 minutes".

Ruby charge les bonnes traductions selon la valeur de de l'expression I18n.locale.


Avoir des templates pour chaque langue

La deuxième solution est d'utiliser des templates localisés. C'est très utile pour les emails ou les pages de contenu, où on a pas une équivalence exacte entre les différents contenus selon les langues ou qu'on utilise des images différentes.

Cela repose sur le système de rendu de Rails, qui utilise les conventions de nommage des fichiers de vues. Par exemple, si l'application utilise la locale fr et qu'on accède à la page home, Rails va chercher les vues dont le nom commence par home et — s'il y en a plusieurs — se décider.

Ainsi, si une vue nommée home.fr.html.erb est composés de plusieurs morceaux (tous optionnels en dehors du premier) que Rails comprend grâce à leur ordre. Il sait que fr correspond à la locale, que html correspond au format de réponse attendue (on aura souvent des templates différents quand la page est appelée en JSON ou en HTML, par exemple) et que erb correspond au moteur de template (Haml, Slim, ERB, etc.) utilisé pour interpréter le code.

D'ailleurs, ce système est poussé plus en avant pour les mails grâce au mécanisme de multipart, qui permet d'envoyer dans le même mail le format texte et le format HTML !


Faire ça uniquement côté Javascript

La dernière solution est très utile quand on développe une application riche basée sur Javascript (Backbone, Angular, etc.). Elle consiste à transformer les fichiers de configuration YAML en fichiers Javascript pour envoyer les traductions au navigateur et laisser Javascript faire la substitution.

Des outils comme I18n JS permettent ça et peuvent être utilisés avec n'importe quel langage (cf. le bas de la page du projet) !


RE: Stocker du texte hors des vues, les solutions? - Malya - 02-03-2013

Je rajoute une question mais concernant la traduction elle-même. Si on utilise par exemple java pour tout coder, il faut alors écrire chaque mot/phrase à traduire?

Tout comme si on utilise des trucs tout fait, il y a de grands risques d'erreurs de traduction non?
Parce qu'à la limite, messages de bienvenue, dates et heures, ça passe, mais il avait été question de faire le site entier en plusieurs langues, je suppose que les règles et autres petites indications sont inclus dedans.


RE: Stocker du texte hors des vues, les solutions? - Sephi-Chan - 02-03-2013

(02-03-2013, 05:12 PM)Malya a écrit : Je rajoute une question mais concernant la traduction elle-même. Si on utilise par exemple java pour tout coder, il faut alors écrire chaque mot/phrase à traduire?

Tout comme si on utilise des trucs tout fait, il y a de grands risques d'erreurs de traduction non?
Parce qu'à la limite, messages de bienvenue, dates et heures, ça passe, mais il avait été question de faire le site entier en plusieurs langues, je suppose que les règles et autres petites indications sont inclus dedans.

En dehors des outils disponibles pour t'aider, le langage utilisé n'a pas d'incidence sur le travail de traduction requis.

Bien sûr qu'en l'absence de magie, il faut tout traduire. :o


Sephi-Chan, perplexe… :heuuu:


RE: Stocker du texte hors des vues, les solutions ? - Xenos - 04-03-2013

(en suite à la question de Zappada sur les multiples BDD)

Principe
On stocke les textes de traduction ("localization") dans un fichier XML, qui sera ensuite compilé en PHP pour accélérer l'affichage des pages.
La traduction (recherche du bon texte pour la langue choisie par l'utilisateur) se fait coté serveur.

Langages utilisés:
XML pour stocker les textes bruts.
PHP pour la traduction coté serveur, oujavascript/XMLHttpRequest pour la traduction coté client.

Description

Dans mon cas, j'ai utilisé un système très similaire [à celui d'avoir des textes dans la BDD, appelés par une fonction + argument unique au texte à traduire], mais plus performant, car il ne requiert pas d'appeler la BDD:

XML
Code :
<?xml version="1.0" encoding="utf-8"?>

<localization lang="fr"    project="reinom">
    <stream>
        <html>
            <n name="generic">
                <t name="description">La plateforme Reinom rassemble des jeux par navigateur et des services web sur un seul portail pour une facilité d'utilisation accrue.</t>
                <t name="title">Reinom - Jeux et services web</t>
                <t name="keywords">Reinom, plateforme, jeux, service web</t>
                <t name="author">Xenos (Vincent MONIER)</t>
            </n>
            <n name="headingbar">
                <n name="title">
                    <t name="reinom">Liste des jeux et services webs disponibles.</t>
                    <t name="news">Fil d'actualité de la communauté.</t>
                    <t name="members">Les membres de la communauté Reinom.</t>
                    <t name="money">Toutes les informations financières sur Reinom sont publiques: consultez-les.</t>
                    <t name="contacts">Contactez un membre de l'équipe Reinom.</t>
                    <t name="requests">Si vous rencontrez un problème avec la plateforme, venez le signaler ici.</t>
                    <t name="messages" params="new_messages messages">
                        <if conditions="$0 EQ 0 and $1 EQ 0">Vous n'avez aucun message.</if>
                        <if conditions="$0 EQ 0 and $1 EQ 1">Vous n'avez aucun nouveau message et 1 message déjà lu.</if>
                        <if conditions="$0 EQ 0 and $1 GT 1">Vous n'avez aucun nouveau message et $1 messages déjà lus.</if>
                        <if conditions="$0 EQ 1 and $1 EQ 0">Vous avez 1 nouveau message.</if>
                        <if conditions="$0 EQ 1 and $1 EQ 1">Vous avez 1 nouveau message et 1 message déjà lu.</if>
                        <if conditions="$0 EQ 1 and $1 GT 1">Vous avez 1 nouveau message et $1 messages déjà lus.</if>
                        <if conditions="$0 GT 1 and $1 EQ 0">Vous avez $0 nouveaux messages.</if>
                        <if conditions="$0 GT 1 and $1 EQ 1">Vous avez $0 nouveaux messages.</if>
                        <if conditions="$0 GT 1 and $1 GT 1">Vous avez $0 nouveaux messages.</if>
                    </t>
                </n>
                <n name="alt">
                    <t name="reinom">Reinom.</t>
                    <t name="news">Actualités.</t>
                    <t name="members">Membres.</t>
                    <t name="money">Financement.</t>
                </n>
            </n>
        </html>
    </stream>
</localization>

Ce fichier XML est donc composé d'un noeud principal, "localized", avec comme attribut le nom de projet.
Il contient ensuite des sous-noeuds regroupant les typages des traductions ("stream" pour les flux, "html" pour le flux de sortie html vers le client, aka la page web). Ensuite, on a des noeuds ("n") de traduction, possédant un nom "attribut "name", ce qui permettra d'utiliser "getelementsByTagName"). Chaque texte est une balise "t", avec également un nom.
Le texte peut contenir des text-nodes (traduction), et des noeuds conditionnels ("if") dont le contenu-texte n'est affiché que si la condition est remplie. Ce système permet de faire des accords (pluriel) ou des cas particulier ("vous n'avez pas de message"/"vous avez de nouveaux messages).

Ce fichier xml traduit tout le site (ou tout un bout de site) pour UNE langue donnée.

PHP
Ce fichier est ensuite compilé en php pour accélérer les traitements. SI la traduction se fait coté client, la compilation est inutile.
Code PHP :
<?php
namespace localized\fr\reinom\stream\html\generic
{
const
description='La plateforme Reinom rassemble des jeux par navigateur et des services web sur un seul portail pour une facilité d\'utilisation accrue.';
const
title='Reinom - Jeux et services web';
const
keywords='Reinom, plateforme, jeux, service web';
const
author='Xenos (Vincent MONIER)';
}
namespace
localized\fr\reinom\stream\html\headingbar
{
}
namespace
localized\fr\reinom\stream\html\headingbar\title
{
const
reinom='Liste des jeux et services webs disponibles.';
const
news='Fil d\'actualité de la communauté.';
const
members='Les membres de la communauté Reinom.';
const
money='Toutes les informations financières sur Reinom sont publiques: consultez-les.';
const
contacts='Contactez un membre de l\'équipe Reinom.';
const
requests='Si vous rencontrez un problème avec la plateforme, venez le signaler ici.';
const
register='Inscrivez-vous sur Reinom.';
const
login='Connexion.';
const
events='Votre fil d\'actualités personnelles.';
const
logout='Déconnexion.';
const
preferences='Modifiez les paramètres de votre compte.';
}

Le "namespace" est issu du balisage XML. Le nom de chaque constante est issu du nom de la balise "t".

Pour l'utiliser, il me suffit d'appeler la constante qui va bien (localized\fr\reinom\stream\html\headingbar\title\news par exemple). Je n'ai pas encore trouvé de beau moyen pour récupérer les conditions (balises "if").

Javascript
Si on veut traduire coté client et non coté serveur, on peut utiliser XMLHttpRequest pour récupérer le fichier XML (en cache ou non). Une fois récupéré, il faut avoir une liste, dans la page web, des emplacements des textes à traduire, avec le chemin xml du texte. A partir de ces 3 informations (emplacement html, chemin xml, fichier xml), le javascript peut traduire la page coté client. Si on change de langue, il suffit de re-charger le xml.

Avantages:
  • Flexibilité (ma propre norme)
  • Portabilité (XML; je peux déporter le calcul vers le client plutôt que sur le serveur)
  • Ajout possible de langues
  • Possibilité de mixer les langues (prendre le texte français en 1er, sinon l'anglais, sinon l'allemand etc)
  • Possibilité d'ajouter facilement des langues/textes
  • Symétrie totale des langues (il n'y a pas une langue prépondérante, ce que j'aurai eu si j'avais utilisé le français comme langue de base pour le traduire ensuite)
  • Possibilité d'ajout des balises de votes/appréciation des différentes traductions pour que les utilisateurs puissent voter pour/contre une traduction
  • Possibilité d'avoir plusieurs traductions d'un même texte dans un seul fichier XML (plusieurs noeuds "t" avec le même "name", mais des dates de créations, attribut "date", différentes)
  • La compilation XML=>PHP est réalisable via un simple fichier XSL

Avenir
Je normaliserai ce principe sur le site de Reinom, avec les outils qu'il faut pour l'utiliser (type open-source): le XSLD/DTD du document XML, le fichier de compilation XML vers PHP, le principe d'utilisation en PHP, le singleton PHP pour la traduction (et sa doc générique, hors langage), ainsi que les pistes pour la traduction coté client ainsi que ses avantages/inconvénients.

Message édité
Ajout de l'avantage "La compilation XML=>PHP est réalisable via un simple fichier XSL": puisque le fichier-source est en XML, le compilateur peut être réalisé dans le langage XSL, qui a l'atout d'être portable, plutôt rapide, normalisé et implémenté dans de nombreux autres langages (il existe des fonctions déjà faites pour appliquer un XSL à un fichier XML que ce soit en JAVA, en PHP, en javascript, en C/C++ ou en tout un tas d'autres langages usuels)