Subversion Repositories Applications.framework

Rev

Details | Last modification | View Log | RSS feed

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