Fixes #149
[akelos.git] / lib / AkLocaleManager.php
blob8ab58e3d7e71adbb939054042a112ddd5b277e95
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4 // +----------------------------------------------------------------------+
5 // | Akelos Framework - http://www.akelos.org |
6 // +----------------------------------------------------------------------+
7 // | Copyright (c) 2002-2006, Akelos Media, S.L. & Bermi Ferrer Martinez |
8 // | Released under the GNU Lesser General Public License, see LICENSE.txt|
9 // +----------------------------------------------------------------------+
11 /**
12 * @package ActiveSupport
13 * @subpackage I18n-L10n
14 * @author Bermi Ferrer <bermi a.t akelos c.om>
15 * @copyright Copyright (c) 2002-2006, Akelos Media, S.L. http://www.akelos.org
16 * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html>
19 if(!defined('AK_AVAILABLE_LOCALES')){
20 define('AK_AVAILABLE_LOCALES',AK_FRAMEWORK_LANGUAGE);
23 require_once(AK_LIB_DIR.DS.'AkObject.php');
25 defined('AK_FRAMEWORK_LANGUAGE') ? null : define('AK_FRAMEWORK_LANGUAGE', 'en');
27 class AkLocaleManager extends AkObject
30 var $available_locales = array(AK_FRAMEWORK_LANGUAGE=>array(AK_FRAMEWORK_LANGUAGE));
31 var $browser_lang = array(AK_FRAMEWORK_LANGUAGE);
33 function init()
35 if(AK_AVAILABLE_LOCALES == 'auto'){
36 $this->available_locales = $this->_getAvailableLocales();
37 }elseif(AK_AVAILABLE_LOCALES != 'en'){
38 $this->available_locales = $this->_parseLocaleConfigString(AK_AVAILABLE_LOCALES);
42 function _getAvailableLocales()
44 static $available_locales;
46 if(empty($available_locales)){
47 $available_locales = array();
48 $d = dir(AK_CONFIG_DIR.DS.'locales');
49 while (false !== ($entry = $d->read())) {
50 if (preg_match('/\\.php$/', $entry)){
51 $locale = str_replace('.php','',$entry);
52 $available_locales[$locale] = array($locale);
55 $d->close();
58 return $available_locales;
61 function _parseLocaleConfigString($locale_settings)
63 $locale_settings = trim(str_replace(' ','',$locale_settings));
64 $locale_settings = str_replace(array(';','(',')'), array(',','~','',''),$locale_settings);
65 $available_locales = strstr($locale_settings,',') ? explode(',',$locale_settings) : array($locale_settings);
66 $locales = array();
67 foreach ($available_locales as $locale_string){
68 if(strstr($locale_string,'~')){
69 $tmp_arr = explode('~',$locale_string);
70 $locale_string = $tmp_arr[0];
71 $locale_alias = array($locale_string);
72 if(strstr($tmp_arr[1],'|')){
73 $locale_alias = array_merge($locale_alias, explode('|',$tmp_arr[1]));
74 }else{
75 $locale_alias = array_merge($locale_alias, array($tmp_arr[1]));
77 }else {
78 $locale_alias = array($locale_string);
82 $locales[trim($locale_string)] = $locale_alias;
85 return $locales;
88 function getBrowserLanguages()
90 $browser_accepted_languages = str_replace('-','_', strtolower(preg_replace('/q=[0-9\.]+,*/','',@$_SERVER['HTTP_ACCEPT_LANGUAGE'])));
91 $browser_languages = (array_diff(split(';|,',$browser_accepted_languages.','), array('')));
92 if(empty($browser_languages)){
93 return array($this->_getDefaultLocale());
95 return array_unique($browser_languages);
99 function getDefaultLanguageForUser()
101 $browser_languages = $this->getBrowserLanguages();
103 // First run for full locale (en_us, en_uk)
104 foreach ($browser_languages as $browser_language){
105 if(isset($this->available_locales[$browser_language])){
106 return $browser_language;
110 // Second run for only language code (en, es)
111 foreach ($browser_languages as $browser_language){
112 if($pos = strpos($browser_language,'_')){
113 $browser_language = substr($browser_language,0, $pos);
114 if(isset($this->available_locales[$browser_language])){
115 return $browser_language;
119 return $this->_getDefaultLocale();
122 function _getDefaultLocale()
124 $available_locales = $this->available_locales;
125 $default_locale = array_shift($available_locales);
126 return is_array($default_locale) ? $default_locale[0] : $default_locale;
130 function getUsedLanguageEntries($lang_entry = null, $controller = null)
132 static $_locale_entries = array();
134 if(isset($controller)){
135 $_locale_entries[$controller][$lang_entry] = $lang_entry;
136 } else {
137 $_locale_entries[$lang_entry] = $lang_entry;
140 if(!isset($lang_entry)){
141 return $_locale_entries;
146 * @todo Refactor this method
148 function updateLocaleFiles()
150 $new_core_entries = array();
151 $new_controller_entries = array();
152 $new_controller_files = array();
153 $used_entries = AkLocaleManager::getUsedLanguageEntries();
154 require(AK_CONFIG_DIR.DS.'locales'.DS.AK_FRAMEWORK_LANGUAGE.'.php');
155 $core_dictionary = $dictionary;
156 $controllers_dictionaries = array();
158 foreach ($used_entries as $k=>$v){
159 // This is a controller file
160 if(is_array($v)){
161 if(!isset($controllers_dictionaries[$k])){
162 $controller = $k;
163 $module_lang_file = AK_APP_DIR.DS.'locales'.DS.$controller.DS.AK_FRAMEWORK_LANGUAGE.'.php';
164 if(is_file($module_lang_file)){
165 require($module_lang_file);
166 $controllers_dictionaries[$controller] = array_merge((array)$dictionary, (array)$v);
167 $existing_controllers_dictionaries[$controller] = (array)$dictionary;
168 }else{
169 $controllers_dictionaries[$controller] = (array)$v;
170 $new_controller_files[$controller] = $module_lang_file;
173 }else {
174 if(!isset($core_dictionary[$k])){
175 $new_core_entries[$k] = $k;
180 $dictionary_file = '';
181 foreach ($new_controller_files as $controller=>$file_name){
182 $dictionary_file = "<?php\n\n// File created on: ".date("Y-m-d G:i:s",Ak::time())."\n\n\$dictionary = array();\n\n";
183 foreach ($controllers_dictionaries[$controller] as $k=>$entry){
184 $entry = str_replace("'","\\'",$entry);
185 $dictionary_file .= "\n\$dictionary['$entry'] = '$entry';";
187 unset($controllers_dictionaries[$controller]);
188 $dictionary_file .= "\n\n\n?>";
189 Ak::file_put_contents($file_name,$dictionary_file);
192 // Module files
193 foreach ((array)$controllers_dictionaries as $controller => $controller_entries){
194 $dictionary_file = '';
195 foreach ($controller_entries as $entry){
196 if($entry == '' || isset($existing_controllers_dictionaries[$controller][$entry])) {
197 continue;
199 $entry = str_replace("'","\\'",$entry);
200 $dictionary_file .= "\n\$dictionary['$entry'] = '$entry';";
202 if($dictionary_file != ''){
203 $original_file = Ak::file_get_contents(AK_APP_DIR.DS.'locales'.DS.$controller.DS.AK_FRAMEWORK_LANGUAGE.'.php');
204 $original_file = rtrim($original_file,"?> \n\r");
205 $new_entries = "\n\n// ".date("Y-m-d G:i:s",Ak::time())."\n\n".$dictionary_file."\n\n\n?>\n";
206 $dictionary_file = $original_file.$new_entries;
207 Ak::file_put_contents(AK_APP_DIR.DS.'locales'.DS.$controller.DS.AK_FRAMEWORK_LANGUAGE.'.php', $dictionary_file);
209 foreach (Ak::langs() as $lang){
210 if($lang != AK_FRAMEWORK_LANGUAGE){
211 $lang_file = @Ak::file_get_contents(AK_APP_DIR.DS.'locales'.DS.$controller.DS.$lang.'.php');
212 if(empty($lang_file)){
213 $dictionary_file = $original_file;
214 }else{
215 $lang_file = rtrim($lang_file,"?> \n\r");
216 $dictionary_file = $lang_file;
218 Ak::file_put_contents(AK_APP_DIR.DS.'locales'.DS.$controller.DS.$lang.'.php', $dictionary_file.$new_entries);
224 // Core locale files
225 $dictionary_file = '';
226 foreach ($new_core_entries as $core_entry){
227 if($core_entry == '') {
228 continue;
230 $core_entry = str_replace("'","\\'",$core_entry);
231 $dictionary_file .= "\n\$dictionary['$core_entry'] = '$core_entry';";
233 if($dictionary_file != ''){
234 $original_file = Ak::file_get_contents(AK_CONFIG_DIR.DS.'locales'.DS.AK_FRAMEWORK_LANGUAGE.'.php');
235 $original_file = rtrim($original_file,"?> \n\r");
236 $new_entries = "\n\n// ".date("Y-m-d G:i:s",Ak::time())."\n\n".$dictionary_file."\n\n\n?>\n";
237 $dictionary_file = $original_file.$new_entries;
238 Ak::file_put_contents(AK_CONFIG_DIR.DS.'locales'.DS.AK_FRAMEWORK_LANGUAGE.'.php', $dictionary_file);
239 foreach (Ak::langs() as $lang){
240 if($lang != AK_FRAMEWORK_LANGUAGE){
241 $lang_file = Ak::file_get_contents(AK_CONFIG_DIR.DS.'locales'.DS.$lang.'.php');
242 if(empty($lang_file)){
243 $dictionary_file = str_replace("\$locale['description'] = 'English';","\$locale['description'] = '$lang';", $original_file);
244 }else{
245 $lang_file = rtrim($lang_file,"?> \n\r");
246 $dictionary_file = $lang_file;
248 Ak::file_put_contents(AK_CONFIG_DIR.DS.'locales'.DS.$lang.'.php', $dictionary_file.$new_entries);
257 * The following functions are for handling i18n when using url based interfaces
261 function initApplicationInternationalization(&$Request)
263 if(!defined('AK_APP_LOCALES')){
264 define('AK_APP_LOCALES',join(',',array_keys($this->available_locales)));
266 $lang = $this->_getLocaleForRequest($Request);
268 $this->rememberNavigationLanguage($lang);
270 $Request->_request['lang'] = $lang;
271 $Request->lang = $lang;
275 * Returns an array which locales enabled on the public website.
276 * In order to define available languages you must define AK_PUBLIC_LOCALES
277 * which a comma-separated list of locales
279 * @return array
281 function getPublicLocales()
283 static $public_locales;
284 if(empty($public_locales)){
285 $public_locales = defined('AK_PUBLIC_LOCALES') ?
286 Ak::toArray(AK_PUBLIC_LOCALES) :
287 array_keys($this->available_locales);
289 return $public_locales;
292 function _getLocaleForRequest(&$Request)
294 $lang = $this->getNavigationLanguage();
296 if($url_locale = $this->getLangFromUrl($Request)){
297 $lang = $this->getLocaleFromAlias($url_locale);
300 if(!$this->_canUseLocaleOnCurrentRequest($lang, $Request)){
301 $lang = array_shift($this->getPublicLocales());
302 }elseif (empty($lang)){
303 $lang = array_shift($this->getPublicLocales());
306 // This way we store on get_url_locale and on lang the value of $lang on
307 // a static variable for accessing it application wide
308 empty($url_locale) ? null : Ak::get_url_locale($url_locale);
309 Ak::lang($lang);
311 return $lang;
314 function _canUseLocaleOnCurrentRequest($lang, &$Request)
316 return in_array($lang, $this->getPublicLocales());
320 function getLangFromUrl(&$Request)
322 $lang = false;
324 if(isset($Request->lang)){
325 return $Request->lang;
328 if(isset($Request->ak)){
329 $regex_arr = array();
330 $match = false;
332 foreach ($this->available_locales as $lang=>$aliases){
333 foreach ($aliases as $alias){
334 $regex_arr[] = '('.$alias.')(\/){1}';
337 $regex = '/^('.join('|',$regex_arr).'){1}/';
339 if (preg_match($regex, trim($Request->ak,'/').'/', $match)){
340 $lang = trim($match[0],'/');
341 if(empty($lang)){
342 unset($Request->_request['ak'], $Request->ak);
343 }else{
344 $Request->ak = $Request->_request['ak'] = ltrim(substr_replace(trim($Request->ak,'/'),'',0,strlen($lang)), '/');
346 }else {
347 return false;
351 $lang = isset($Request->lang) ? $Request->lang : $lang;
353 return $lang;
356 function rememberNavigationLanguage($lang)
358 if(isset($_SESSION) && !empty($lang)){
359 $_SESSION['lang'] = $lang;
363 function getNavigationLanguage()
365 if(!isset($_SESSION['lang'])){
366 $this->browser_lang = $this->getDefaultLanguageForUser();
367 return $this->getDefaultLanguageForUser();
368 }else{
369 return $_SESSION['lang'];
373 function getLocaleFromAlias($alias)
375 foreach ($this->available_locales as $locale=>$locale_arr){
376 if(in_array($alias,$locale_arr)){
377 return $locale;
381 return false;