Revision 1690
Added by darkviper over 12 years ago
ModLanguage.php | ||
---|---|---|
7 | 7 |
* @license http://www.gnu.org/licenses/gpl.html |
8 | 8 |
* @version $Id$ |
9 | 9 |
* @filesource $HeadURL$ |
10 |
* @since Datei vorhanden seit Release 2.8.2
|
|
10 |
* @since Datei vorhanden seit Release 2.8.4
|
|
11 | 11 |
* @lastmodified $Date$ |
12 | 12 |
*/ |
13 | 13 |
class ModLanguage { |
14 | 14 |
|
15 |
// @var string 2 upercase chars for hardcoded system default language |
|
16 |
private $_sSystemLanguage = 'EN'; |
|
17 |
// @var string 2 upercase chars for default fallback language |
|
18 |
private $_sDefaultLanguage = ''; |
|
19 |
// @var string 2 upercase chars for current active language |
|
15 | 20 |
private $_sCurrentLanguage = ''; |
16 |
private $_sDefaultLanguage = '';
|
|
21 |
// @var string full directory with trailing slash to search language files in
|
|
17 | 22 |
private $_sLanguageDirectory = ''; |
18 |
private $_sLanguageFile = ''; |
|
19 |
private $_LanguageTable = array(); |
|
23 |
// @array list to hold the complete resulting translation table |
|
24 |
private $_aLanguageTable = array(); |
|
25 |
// @array list of all loaded/merged languages |
|
26 |
private $_aLoadedLanguages = array(); |
|
27 |
|
|
28 |
// @boolean set to TRUE if language is successfully loaded |
|
20 | 29 |
private $_bLoaded = false; |
30 |
// @object hold the Singleton instance |
|
31 |
private static $_oInstance = null; |
|
21 | 32 |
|
22 |
private static $_oInstance = null; |
|
23 |
/* prevent from public instancing */ |
|
24 |
protected function __construct() { } |
|
25 |
/* prevent from cloning */ |
|
26 |
private function __clone() {} |
|
27 | 33 |
/** |
34 |
* prevent class from public instancing |
|
35 |
*/ |
|
36 |
final protected function __construct() { } |
|
37 |
/** |
|
38 |
* prevent from cloning existing instance |
|
39 |
*/ |
|
40 |
final private function __clone() {} |
|
41 |
/** |
|
28 | 42 |
* get a valid instance of this class |
29 | 43 |
* @return object |
30 | 44 |
*/ |
... | ... | |
36 | 50 |
return self::$_oInstance; |
37 | 51 |
} |
38 | 52 |
/** |
53 |
* return requested translation for a key |
|
54 |
* @param string $sLanguageKey 2-uppercase letters language code |
|
55 |
* @return string found translation or empty string |
|
56 |
* @throws TranslationException |
|
57 |
*/ |
|
58 |
public function __get($sLanguageKey) |
|
59 |
{ |
|
60 |
if($this->_bLoaded) { |
|
61 |
$sRetval = (isset($this->_aLanguageTable[$sLanguageKey]) |
|
62 |
? $this->_aLanguageTable[$sLanguageKey] : '{missing: '.$sLanguageKey.'}'); |
|
63 |
return $sRetval; |
|
64 |
} |
|
65 |
$msg = 'No translation table loaded'; |
|
66 |
throw new TranslationException($msg); |
|
67 |
} |
|
68 |
/** |
|
69 |
* returns the whoole language array for use in templateengine |
|
70 |
* @return array |
|
71 |
* @throws TranslationException |
|
72 |
*/ |
|
73 |
public function getLangArray() |
|
74 |
{ |
|
75 |
if($this->_bLoaded) { |
|
76 |
return $this->_aLanguageTable; |
|
77 |
} |
|
78 |
$msg = 'No translation table loaded'; |
|
79 |
throw new TranslationException($msg); |
|
80 |
} |
|
81 |
/** |
|
39 | 82 |
* set language and load needed language file |
40 | 83 |
* @param string $sDirectory full path to the language files |
41 |
* @param string $sLanguage 2-letters language code |
|
42 |
* @param string $sDefault 2-letters default-language code |
|
84 |
* @param string $sLanguage 2 chars current active language code |
|
85 |
* @param string $sDefault 2 chars default fallback language code |
|
86 |
* @throws SecDirectoryTraversalException [global exception] |
|
87 |
* @throws TranslationException [private exception] |
|
43 | 88 |
*/ |
44 |
public function setLanguage($sDirectory, $sLanguage, $sDefault = 'EN')
|
|
89 |
public function setLanguage($sDirectory, $sCurrentLanguage, $sDefaultLanguage = 'EN')
|
|
45 | 90 |
{ |
91 |
// sanitize arguments |
|
46 | 92 |
$sBasePath = realpath(dirname(dirname(__FILE__))); |
47 |
$sLangDir = realpath($sDirectory); |
|
48 |
if(!preg_match('/^'.preg_quote($sBasePath, '/').'/', $sLangDir)) { |
|
49 |
throw new SecDirectoryTraversalException(); |
|
50 |
} |
|
51 |
$sLangDir = str_replace('\\', '/', $sLangDir); |
|
52 |
$sLangDir = rtrim($sLangDir, '/').'/'; |
|
53 |
$sLanguage = strtoupper($sLanguage); |
|
54 |
$sLanguage = strtoupper($sDefault); |
|
55 |
if($this->_sLanguageDirectory != $sLangDir || |
|
56 |
$this->_sCurrentLanguage != $sLanguage || |
|
57 |
$this->_sDefaultLanguage != $sDefault) |
|
58 |
{ |
|
59 |
// only load language if not already loaded |
|
60 |
$this->_sLanguageDirectory = rtrim($sLangDir, '/').'/'; |
|
61 |
$this->_sCurrentLanguage = $sLanguage; |
|
62 |
$this->_sDefaultLanguage = $sDefault; |
|
63 |
|
|
64 |
if(!$this->_findLanguageFile()) { |
|
93 |
$sLangDir = realpath($sDirectory); |
|
94 |
if(preg_match('/^'.preg_quote($sBasePath, '/').'/', $sLangDir)) { |
|
95 |
$sLangDir = rtrim(str_replace('\\', '/', $sLangDir), '/').'/'; |
|
96 |
$sCurrentLanguage = strtoupper($sCurrentLanguage); |
|
97 |
$sDefaultLanguage = strtoupper($sDefaultLanguage); |
|
98 |
// check if the requested language is not already loaded |
|
99 |
if($this->_sLanguageDirectory != $sLangDir || |
|
100 |
$this->_sCurrentLanguage != $sCurrentLanguage || |
|
101 |
$this->_sDefaultLanguage != $sDefaultLanguage) |
|
102 |
{ |
|
103 |
// now load and merge the files in order SYSTEM - DEFAULT - CURRENT |
|
104 |
$this->_aLanguageTable = array(); |
|
105 |
// at first search SYSTEM_LANGUAGE |
|
106 |
$this->_loadLanguage($sLangDir, $this->_sSystemLanguage); |
|
107 |
// at second merge DEFAULT_LANGUAGE |
|
108 |
if(!in_array($sDefaultLanguage, $this->_aLoadedLanguages)) { |
|
109 |
$this->_loadLanguage($sLangDir, $sDefaultLanguage); |
|
110 |
} |
|
111 |
// at third merge CURRENT_LANGUAGE |
|
112 |
if(!in_array($sCurrentLanguage, $this->_aLoadedLanguages)) { |
|
113 |
$this->_loadLanguage($sLangDir, $sCurrentLanguage); |
|
114 |
} |
|
115 |
// if no predefined language was fond, search for first available language |
|
116 |
if(sizeof($this->_aLanguageTable) == 0) { |
|
117 |
// if absolutely no language was fond, throw an exception |
|
118 |
if(false !== ($sRandomLanguage = $this->_findFirstLanguage($sLangDir))) { |
|
119 |
$this->_loadLanguage($sLangDir, $sRandomLanguage); |
|
120 |
} |
|
121 |
} |
|
122 |
// remember last settings |
|
123 |
$this->_sLanguageDirectory = $sLangDir; |
|
124 |
$this->_sCurrentLanguage = $sCurrentLanguage; |
|
125 |
$this->_sDefaultLanguage = $sDefaultLanguage; |
|
126 |
} |
|
127 |
if(!($this->_bLoaded = (sizeof($this->_aLanguageTable) != 0))) { |
|
65 | 128 |
$msg = 'unable to find valid language definition file in<br />'; |
66 | 129 |
$msg .= '"'.str_replace($sBasePath, '', $this->_sLanguageDirectory).'"'; |
67 | 130 |
throw new TranslationException($msg); |
68 | 131 |
} |
69 |
$this->_importArrays(); |
|
132 |
$this->_bLoaded = true; |
|
133 |
}else { |
|
134 |
throw new SecDirectoryTraversalException($sLangDir); |
|
70 | 135 |
} |
71 |
$this->_bLoaded = (sizeof($this->_LanguageTable) > 0); |
|
72 | 136 |
} |
73 | 137 |
/** |
74 |
* return requested translation for a key
|
|
75 |
* @param string $sLanguageKey 2-uppercase letters language code
|
|
76 |
* @return string found translation or empty string
|
|
138 |
* load language from given directory
|
|
139 |
* @param string $sLangDir
|
|
140 |
* @param string $sLanguage
|
|
77 | 141 |
*/ |
78 |
public function __get($sLanguageKey)
|
|
142 |
private function _loadLanguage($sLangDir, $sLanguage)
|
|
79 | 143 |
{ |
80 |
$sRetval = (isset($this->_LanguageTable[$sLanguageKey]) |
|
81 |
? $this->_LanguageTable[$sLanguageKey] : '{missing: '.$sLanguageKey.'}'); |
|
82 |
return $sRetval; |
|
144 |
if(is_readable($sLangDir.$sLanguage.'.php')) { |
|
145 |
$this->_aLanguageTable = array_merge($this->_aLanguageTable, |
|
146 |
$this->_importArrays($sLangDir.$sLanguage.'.php')); |
|
147 |
$this->_aLoadedLanguages[] = $sLanguage; |
|
148 |
} |
|
83 | 149 |
} |
84 | 150 |
/** |
85 |
* returns the whoole language array for use in templateengine |
|
86 |
* @return array |
|
151 |
* find first available language in given directory |
|
152 |
* @param string $sLangDir the directory to scan for language files |
|
153 |
* @return string returns the 2 char language code or FALSE if search fails |
|
87 | 154 |
*/ |
88 |
public function getLangArray()
|
|
155 |
private function _findFirstLanguage($sLangDir)
|
|
89 | 156 |
{ |
90 |
return $this->_LanguageTable; |
|
91 |
} |
|
92 |
/** |
|
93 |
* search language file in order: LANGUAGE - DEFAULT_LANGUAGE - FIRST_FOUND |
|
94 |
* @return boolean |
|
95 |
*/ |
|
96 |
private function _findLanguageFile() |
|
97 |
{ |
|
98 |
$bMatch = false; |
|
99 |
$dir = $this->_sLanguageDirectory; |
|
100 |
if(is_readable($dir.$this->_sCurrentLanguage.'.php')) { |
|
101 |
// check actual language |
|
102 |
$this->_sLanguageFile = $dir.$this->_sCurrentLanguage.'.php'; |
|
103 |
$bMatch = true; |
|
104 |
}else { |
|
105 |
if(is_readable($dir.$this->_sDefaultLanguage.'.php')) { |
|
106 |
// check default language |
|
107 |
$this->_sLanguageFile = $dir.$this->_sDefaultLanguage.'.php'; |
|
108 |
$bMatch = true; |
|
109 |
}else { |
|
110 |
// search for first available and readable language file |
|
111 |
if(is_readable($dir)) { |
|
112 |
$iterator = new DirectoryIterator($dir); |
|
113 |
foreach ($iterator as $fileinfo) { |
|
114 |
if(!preg_match('/^[A-Z]{2}\.php$/', $fileinfo->getBasename())) { continue; } |
|
115 |
$sLanguageFile = str_replace('\\', '/', $fileinfo->getPathname()); |
|
116 |
if(is_readable($sLanguageFile)) { |
|
117 |
$this->_sLanguageFile = $sLanguageFile; |
|
118 |
$bMatch = true; |
|
119 |
break; |
|
120 |
} |
|
121 |
} |
|
157 |
// search for first available and readable language file |
|
158 |
$sRetval = false; |
|
159 |
if(is_readable($sLangDir)) { |
|
160 |
$iterator = new DirectoryIterator($sLangDir); |
|
161 |
foreach ($iterator as $fileinfo) { |
|
162 |
if(!preg_match('/^[A-Z]{2}\.php$/', $fileinfo->getBasename())) { continue; } |
|
163 |
$sLanguageFile = $fileinfo->getPathname(); |
|
164 |
if(is_readable($sLanguageFile)) { |
|
165 |
$sRetval = basename($sLanguageFile, '.php'); |
|
166 |
break; |
|
122 | 167 |
} |
123 | 168 |
} |
124 | 169 |
} |
125 |
return $bMatch;
|
|
170 |
return $sRetval;
|
|
126 | 171 |
} |
127 | 172 |
/** |
128 | 173 |
* import key-values from language file |
174 |
* @param string $sLanguageFile |
|
175 |
* @return array of language definitions |
|
129 | 176 |
*/ |
130 |
private function _importArrays() |
|
177 |
private function _importArrays($sLanguageFile)
|
|
131 | 178 |
{ |
132 |
include($this->_sLanguageFile); |
|
133 |
$aLangSections = array('HEADING', 'TEXT', 'MESSAGE', 'MENU', 'OVERVIEW', 'GENERIC'); |
|
179 |
include($sLanguageFile); |
|
180 |
$aAllVars = get_defined_vars(); |
|
181 |
$aLangSections = array(); |
|
182 |
$aLanguageTable = array(); |
|
183 |
foreach($aAllVars as $key=>$value) { |
|
184 |
// extract the names of arrays from language file |
|
185 |
if(is_array($value)) { |
|
186 |
$aLangSections[] = $key; |
|
187 |
} |
|
188 |
} |
|
134 | 189 |
foreach($aLangSections as $sSection) { |
135 |
if(isset(${$sSection}) && is_array(${$sSection})) {
|
|
136 |
foreach(${$sSection} as $key => $value) {
|
|
137 |
$this->_LanguageTable[$sSection.'_'.$key] = $value;
|
|
138 |
}
|
|
190 |
// walk through all arrays
|
|
191 |
foreach(${$sSection} as $key => $value) { |
|
192 |
// and import all found translations
|
|
193 |
$aLanguageTable[$sSection.'_'.$key] = $value;
|
|
139 | 194 |
} |
140 | 195 |
} |
196 |
return $aLanguageTable; |
|
141 | 197 |
} |
142 | 198 |
} // end class Translate |
143 | 199 |
/** |
144 | 200 |
* Exception class for Translation |
145 | 201 |
*/ |
146 | 202 |
class TranslationException extends AppException {} |
147 |
|
Also available in: Unified diff
ModLanguage modified for auto fallback to DEFAULT_LANGUAGE
globalExceptionHandler added AppException, SecurityException, SecDirectoryTraversalException
Errormessage for old class.database modified