Subversion Repositories Applications.framework

Rev

Rev 232 | Rev 274 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 232 Rev 241
1
<?php
1
<?php
2
// declare(encoding='UTF-8');
2
// declare(encoding='UTF-8');
3
/**
3
/**
4
 * I18n permet de traduire une application à partir de données stockées dans des fichiers ini.
4
 * I18n permet de traduire une application à partir de données stockées dans des fichiers ini.
5
 * Si vous souhaitez utiliser le fonctionnement par défaut vous devrez :
5
 * Si vous souhaitez utiliser le fonctionnement par défaut vous devrez :
6
 * - déposer les fichiers ini dans le dossier définit par la variable de config "chemin_i18n".
6
 * - déposer les fichiers ini dans le dossier définit par la variable de config "chemin_i18n".
7
 * - nommer les fichiers selon la forme "locale.ini" (Ex.: fr.ini ou fr_CH.ini ).
7
 * - nommer les fichiers selon la forme "locale.ini" (Ex.: fr.ini ou fr_CH.ini ).
8
 * 
8
 * 
9
 * Elle offre l'accès en lecture seule aux paramètres des fichiers ini.
9
 * Elle offre l'accès en lecture seule aux paramètres des fichiers ini.
10
 * C'est une Singleton. Une seule classe de traduction peut être instanciée par Application.
10
 * C'est une Singleton. Une seule classe de traduction peut être instanciée par Application.
11
 *
11
 *
12
 * @category	PHP 5.2
12
 * @category	PHP 5.2
13
 * @package	Framework
13
 * @package	Framework
14
 * @author		Jean-Pascal MILCENT <jpm@tela-botanica.org>
14
 * @author		Jean-Pascal MILCENT <jpm@tela-botanica.org>
15
 * @copyright	2010 Tela-Botanica
15
 * @copyright	Copyright (c) 2010, Tela Botanica (accueil@tela-botanica.org)
16
 * @license	http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
16
 * @license	http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
17
 * @license	http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
17
 * @license	http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
18
 * @since 		0.3
18
 * @since 		0.3
19
 * @version	$Id$
19
 * @version	$Id$
20
 * @link		/doc/framework/
20
 * @link		/doc/framework/
21
 */
21
 */
22
 
-
 
23
class I18n {
22
class I18n {
24
	/** Format de traduction utilisant les fichier .ini */
23
	/** Format de traduction utilisant les fichier .ini */
25
	const FORMAT_INI = '.ini';
24
	const FORMAT_INI = '.ini';
26
	
25
	
27
	/** Instance de la classe pointant sur elle même (pour le pattern singleton) */
26
	/** Instance de la classe pointant sur elle même (pour le pattern singleton) */
28
	private static $instance = null;
27
	private static $instance = null;
29
	
28
	
30
	/** Fichiers de traduction disponibles. */
29
	/** Fichiers de traduction disponibles. */
31
	private static $traductions = array();
30
	private static $traductions = array();
32
	
31
	
33
	/** Langue courrante utilisée par l'application. */
32
	/** Langue courrante utilisée par l'application. */
34
	private static $langue = null;
33
	private static $langue = null;
-
 
34
	
-
 
35
	/** Tableau des noms des paramètres à définir dans le fichier de config car obligatoirement nécessaire à cette classe.*/
-
 
36
	private static $parametres_obligatoires = array('chemin_i18n', 'i18n_url_parametre', 'i18n_langue_defaut', 'fw_debogage');
35
	
37
	
36
	private function __construct() {
38
	private function __construct() {
37
		self::verifierParametresConfig();
39
		Config::verifierPresenceParametres(self::$parametres_obligatoires);
38
		self::trouverLangue();
40
		self::trouverLangue();
39
	}
41
	}
40
	
42
	
41
	/**
43
	/**
42
	 * Accesseur pour la valeur d'une traduction
44
	 * Accesseur pour la valeur d'une traduction
43
	 * @param string $param le nom du paramètre
45
	 * @param string $param le nom du paramètre
44
	 * @return string la valeur du paramètre
46
	 * @return string la valeur du paramètre
45
	 */
47
	 */
46
	public static function get($identifiant, $langue = null) {
48
	public static function get($identifiant, $langue = null) {
47
		self::verifierCreationInstance();
49
		self::verifierCreationInstance();
48
		$texte = '';
50
		$texte = '';
49
		
51
		
50
		// Récupération de la langue actuellement demandée
52
		// Récupération de la langue actuellement demandée
51
		$langue_a_charger = self::$langue;
53
		$langue_a_charger = self::$langue;
52
		if (!is_null($langue)) {
54
		if (!is_null($langue)) {
53
			$langue_a_charger = $langue;
55
			$langue_a_charger = $langue;
54
		}
56
		}
55
		
57
		
56
		if (!isset(self::$traductions[$langue_a_charger])) {
58
		if (!isset(self::$traductions[$langue_a_charger])) {
57
			// Tentative de chargement du fichier de traduction
59
			// Tentative de chargement du fichier de traduction
58
			$chargement = self::charger($langue_a_charger);
60
			$chargement = self::charger($langue_a_charger);
59
			if ($chargement === false) {
61
			if ($chargement === false) {
60
				$m = "Le fichier d'i18n pour la langue '$langue_a_charger' demandée n'a pas été trouvé.";
62
				$m = "Le fichier d'i18n pour la langue '$langue_a_charger' demandée n'a pas été trouvé.";
61
				self::ajouterErreur($m);
63
				self::ajouterErreur($m);
62
			}
64
			}
63
		}
65
		}
64
		
66
		
65
		// Recherche de la langue dans le tableau des traductions
67
		// Recherche de la langue dans le tableau des traductions
66
		if (isset(self::$traductions[$langue_a_charger]) && self::$traductions[$langue_a_charger] !== false) {
68
		if (isset(self::$traductions[$langue_a_charger]) && self::$traductions[$langue_a_charger] !== false) {
67
			// Recherche de la traduction demandée
69
			// Recherche de la traduction demandée
68
			$valeur = self::getValeur($identifiant, self::$traductions[$langue_a_charger]);
70
			$valeur = self::getValeur($identifiant, self::$traductions[$langue_a_charger]);
69
			if ($valeur !== false) {
71
			if ($valeur !== false) {
70
				$texte = $valeur;
72
				$texte = $valeur;
71
			} else {
73
			} else {
72
				$m = "Le traduction n'existe pas pour l'identifiant '$identifiant' demandé.";
74
				$m = "Le traduction n'existe pas pour l'identifiant '$identifiant' demandé.";
73
				self::ajouterErreur($m);
75
				self::ajouterErreur($m);
74
			}
76
			}
75
		}
77
		}
76
		
78
		
77
		return $texte;
79
		return $texte;
78
	}
80
	}
79
	
81
	
80
	/**
82
	/**
81
	 * Charge un fichier ini dans le tableau des paramètres de l'appli
83
	 * Charge un fichier ini dans le tableau des paramètres de l'appli
82
	 * @param string $fichier_ini le nom du fichier à charger
84
	 * @param string $fichier_ini le nom du fichier à charger
83
	 * @return boolean true, si le fichier a été trouvé et correctement chargé, sinon false.
85
	 * @return boolean true, si le fichier a été trouvé et correctement chargé, sinon false.
84
	 */
86
	 */
85
	public static function charger($langue, $fichier = null, $format = self::FORMAT_INI) {
87
	public static function charger($langue, $fichier = null, $format = self::FORMAT_INI) {
86
		self::verifierCreationInstance();
88
		self::verifierCreationInstance();
87
		$ok = false;
89
		$ok = false;
88
		
90
		
89
		// Création du chemin vers le fichier de traduction par défaut
91
		// Création du chemin vers le fichier de traduction par défaut
90
		if (is_null($fichier)) {
92
		if (is_null($fichier)) {
91
			$fichier = Config::get('chemin_i18n').$langue.$format;
93
			$fichier = Config::get('chemin_i18n').$langue.$format;
92
		}
94
		}
93
 
95
 
94
		// Chargement		
96
		// Chargement		
95
		if ($format == self::FORMAT_INI) {
97
		if ($format == self::FORMAT_INI) {
96
			$ok = self::chargerFichierIni($fichier, $langue);
98
			$ok = self::chargerFichierIni($fichier, $langue);
97
		} else {
99
		} else {
98
			$m = "Le format '$format' de fichier de traduction n'est pas pris en compte par le Framework.";
100
			$m = "Le format '$format' de fichier de traduction n'est pas pris en compte par le Framework.";
99
			self::ajouterErreur($m);
101
			self::ajouterErreur($m);
100
		}
102
		}
101
		
103
		
102
		return $ok;
104
		return $ok;
103
	}
105
	}
104
	
106
	
105
	/**
107
	/**
106
	 * Définit la langue utiliser pour rechercher une traduction.
108
	 * Définit la langue utiliser pour rechercher une traduction.
107
	 * @param string $fichier_ini le nom du fichier à charger
109
	 * @param string $fichier_ini le nom du fichier à charger
108
	 * @return array le fichier ini parsé
110
	 * @return array le fichier ini parsé
109
	 */
111
	 */
110
	public static function setLangue($langue) {
112
	public static function setLangue($langue) {
111
		self::verifierCreationInstance();
113
		self::verifierCreationInstance();
112
		self::$langue = $langue;
114
		self::$langue = $langue;
113
	}
115
	}
114
	
116
	
115
	/**
117
	/**
116
	 * Renvoie la valeur demandé grâce une chaine de paramètres
118
	 * Renvoie la valeur demandé grâce une chaine de paramètres
117
	 * @param string $param la chaine identifiante
119
	 * @param string $param la chaine identifiante
118
	 * @param array $i18n le tableau de traductions
120
	 * @param array $i18n le tableau de traductions
119
	 * @return mixed la valeur correspondante à la chaine identifiante si elle est trouvée, sinon false.
121
	 * @return mixed la valeur correspondante à la chaine identifiante si elle est trouvée, sinon false.
120
	 */
122
	 */
121
	private static function getValeur($param, $i18n) {
123
	private static function getValeur($param, $i18n) {
122
		if ($param === null) {
124
		if ($param === null) {
123
			return false;
125
			return false;
124
		} else {
126
		} else {
125
			if (isset($i18n[$param])) {
127
			if (isset($i18n[$param])) {
126
				return $i18n[$param];
128
				return $i18n[$param];
127
			} else if (strpos($param, '.') !== false) {
129
			} else if (strpos($param, '.') !== false) {
128
				$pieces = explode('.', $param, 2);
130
				$pieces = explode('.', $param, 2);
129
				if (strlen($pieces[0]) && strlen($pieces[1])) {
131
				if (strlen($pieces[0]) && strlen($pieces[1])) {
130
					if (isset($i18n[$pieces[0]])) {
132
					if (isset($i18n[$pieces[0]])) {
131
					   if (is_array($i18n[$pieces[0]])) {
133
					   if (is_array($i18n[$pieces[0]])) {
132
					   		return self::getValeur($pieces[1], $i18n[$pieces[0]]);
134
					   		return self::getValeur($pieces[1], $i18n[$pieces[0]]);
133
					   }
135
					   }
134
					}
136
					}
135
				}
137
				}
136
			} else {
138
			} else {
137
				return false;
139
				return false;
138
			}
140
			}
139
		}
141
		}
140
	}
142
	}
141
	
143
	
142
	/**
144
	/**
143
	 * Parse le fichier ini donné en paramètre
145
	 * Parse le fichier ini donné en paramètre
144
	 * @param string $fichier_ini nom du fichier ini à parser
146
	 * @param string $fichier_ini nom du fichier ini à parser
145
	 * @param string $langue la langue correspondant au fichier
147
	 * @param string $langue la langue correspondant au fichier
146
	 * @return boolean true si le chargement c'est bien passé, sinon false.
148
	 * @return boolean true si le chargement c'est bien passé, sinon false.
147
	 */
149
	 */
148
	private static function chargerFichierIni($fichier_ini, $langue) {
150
	private static function chargerFichierIni($fichier_ini, $langue) {
149
		self::$traductions[$langue] = false;
151
		self::$traductions[$langue] = false;
150
		if (file_exists($fichier_ini)) {
152
		if (file_exists($fichier_ini)) {
151
			$ini = parse_ini_file($fichier_ini, true);
153
			$ini = parse_ini_file($fichier_ini, true);
152
			$ini = self::analyserTableauIni($ini);
154
			$ini = self::analyserTableauIni($ini);
153
			self::$traductions[$langue] = $ini;
155
			self::$traductions[$langue] = $ini;
154
		}
156
		}
155
		return (self::$traductions[$langue] === false) ?  false : true;
157
		return (self::$traductions[$langue] === false) ?  false : true;
156
	}
158
	}
157
	
159
	
158
	/**
160
	/**
159
	 * Analyse un tableau de traductions pour évaluer les clés.
161
	 * Analyse un tableau de traductions pour évaluer les clés.
160
	 * @param array $i18n le tableau de traductions
162
	 * @param array $i18n le tableau de traductions
161
	 * @return array le tableau analysé et modifié si nécessaire.
163
	 * @return array le tableau analysé et modifié si nécessaire.
162
	 */
164
	 */
163
	private static function analyserTableauIni($i18n = array()) {
165
	private static function analyserTableauIni($i18n = array()) {
164
		//ATTENTION : il est important de passer la valeur par référence car nous la modifions dynamiquement dans la boucle
166
		//ATTENTION : il est important de passer la valeur par référence car nous la modifions dynamiquement dans la boucle
165
		foreach ($i18n as $cle => &$valeur) {
167
		foreach ($i18n as $cle => &$valeur) {
166
			if (is_array($valeur)) {
168
			if (is_array($valeur)) {
167
				$i18n[$cle] = self::analyserTableauIni($valeur);
169
				$i18n[$cle] = self::analyserTableauIni($valeur);
168
			} else {
170
			} else {
169
				$i18n = self::evaluerCle($i18n, $cle, $valeur);
171
				$i18n = self::evaluerCle($i18n, $cle, $valeur);
170
			}
172
			}
171
		}
173
		}
172
		return $i18n;
174
		return $i18n;
173
	}
175
	}
174
	
176
	
175
	/**
177
	/**
176
	 * Dans le cas des chaines de traduction à sous clé (ex.: cle.souscle), cette méthode
178
	 * Dans le cas des chaines de traduction à sous clé (ex.: cle.souscle), cette méthode
177
	 * évalue les valeurs correspondantes et créée les sous tableaux associés.
179
	 * évalue les valeurs correspondantes et créée les sous tableaux associés.
178
	 * @param array $i18n tableau de traductions (par référence)
180
	 * @param array $i18n tableau de traductions (par référence)
179
	 * @param string $cle la cle dans le tableau
181
	 * @param string $cle la cle dans le tableau
180
	 * @param string $valeur la valeur à affecter
182
	 * @param string $valeur la valeur à affecter
181
	 */
183
	 */
182
	private static function evaluerCle($i18n, $cle, $valeur) {
184
	private static function evaluerCle($i18n, $cle, $valeur) {
183
		if (strpos($cle, '.') !== false) {
185
		if (strpos($cle, '.') !== false) {
184
			unset($i18n[$cle]);
186
			unset($i18n[$cle]);
185
			$pieces = explode('.', $cle, 2);
187
			$pieces = explode('.', $cle, 2);
186
			if (strlen($pieces[0]) && strlen($pieces[1])) {
188
			if (strlen($pieces[0]) && strlen($pieces[1])) {
187
				if (isset($i18n[$pieces[0]]) && !is_array($i18n[$pieces[0]])) {
189
				if (isset($i18n[$pieces[0]]) && !is_array($i18n[$pieces[0]])) {
188
					$m = "Ne peut pas créer de sous-clé pour '{$pieces[0]}' car la clé existe déjà";
190
					$m = "Ne peut pas créer de sous-clé pour '{$pieces[0]}' car la clé existe déjà";
189
					trigger_error($m, E_USER_WARNING);
191
					trigger_error($m, E_USER_WARNING);
190
				} else {
192
				} else {
191
					$i18n[$pieces[0]][$pieces[1]] = $valeur;
193
					$i18n[$pieces[0]][$pieces[1]] = $valeur;
192
					$i18n[$pieces[0]] = self::evaluerCle($i18n[$pieces[0]], $pieces[1], $valeur);
194
					$i18n[$pieces[0]] = self::evaluerCle($i18n[$pieces[0]], $pieces[1], $valeur);
193
				}
195
				}
194
			} else {
196
			} else {
195
				$m = "Clé invalide '$cle'";
197
				$m = "Clé invalide '$cle'";
196
				trigger_error($m, E_USER_WARNING);
198
				trigger_error($m, E_USER_WARNING);
197
			}
199
			}
198
		} else {
200
		} else {
199
			$i18n[$cle] = $valeur;
201
			$i18n[$cle] = $valeur;
200
		}
202
		}
201
		return $i18n;
203
		return $i18n;
202
	}
204
	}
203
	
205
	
204
	/**
206
	/**
205
	 * Cherche l'information sur la langue demandée par l'application
207
	 * Cherche l'information sur la langue demandée par l'application
206
	 */
208
	 */
207
	private static function trouverLangue() {
209
	private static function trouverLangue() {
208
		if (isset($_GET[Config::get('i18n_url_parametre')])) {
210
		if (isset($_GET[Config::get('i18n_url_parametre')])) {
209
			self::$langue = $_GET[Config::get('i18n_url_parametre')];
211
			self::$langue = $_GET[Config::get('i18n_url_parametre')];
210
		} else {
212
		} else {
211
			self::$langue = Config::get('i18n_langue_defaut');
213
			self::$langue = Config::get('i18n_langue_defaut');
212
		}
214
		}
213
	}
215
	}
214
	
216
	
215
	/**
217
	/**
216
	 * Vérifie si l'instance de classe à été crée, si non la crée
218
	 * Vérifie si l'instance de classe à été crée, si non la crée
217
	 */
219
	 */
218
	private static function verifierCreationInstance() {
220
	private static function verifierCreationInstance() {
219
		if (empty(self::$instance)) {
221
		if (empty(self::$instance)) {
220
			self::$instance = new I18n();
222
			self::$instance = new I18n();
221
		}
223
		}
222
	}
224
	}
223
	
-
 
224
	/**
-
 
225
	 * Vérifie que tous les paramêtres de config nécessaires au fonctionnement de cette classe existe dans les fichiers
-
 
226
	 * de configurations.
-
 
227
	 */
-
 
228
	private static function verifierParametresConfig() {
-
 
229
		$ok = true;
-
 
230
		$parametres = array('chemin_i18n', 'i18n_url_parametre', 'i18n_langue_defaut');
-
 
231
		foreach ($parametres as $param) {
-
 
232
			if (is_null(Config::get($param))) {
-
 
233
				$m = "L'utilisation de la classe I18n nécessite de définir '$param' dans un fichier de configuration.";
-
 
234
				self::ajouterErreur($m);
-
 
235
				$ok = false;
-
 
236
			}
-
 
237
		}
-
 
238
		return $ok;
-
 
239
	}
-
 
240
	
225
	
241
	/**
226
	/**
242
	 * Ajouter une message d'erreur
227
	 * Ajouter une message d'erreur
243
	 */
228
	 */
244
	private static function ajouterErreur($m, $e = E_USER_WARNING) {
229
	private static function ajouterErreur($m, $e = E_USER_WARNING) {
245
		if (Config::get('fw_debogage') === true) {
230
		if (Config::get('fw_debogage') === true) {
246
			trigger_error($m, $e);
231
			trigger_error($m, $e);
247
		}
232
		}
248
	}
233
	}
249
}
234
}
250
?>
235
?>