1
|
<?php
|
2
|
/**
|
3
|
* @category WebsiteBaker
|
4
|
* @package WebsiteBaker_Core
|
5
|
* @author Werner v.d.Decken
|
6
|
* @copyright WebsiteBaker Org e.V.
|
7
|
* @license http://www.gnu.org/licenses/gpl.html
|
8
|
* @version $Id: ModLanguage.php 1690 2012-05-31 10:56:58Z darkviper $
|
9
|
* @filesource $HeadURL: svn://isteam.dynxs.de/wb-archiv/branches/2.8.x/wb/framework/ModLanguage.php $
|
10
|
* @since Datei vorhanden seit Release 2.8.4
|
11
|
* @lastmodified $Date: 2012-05-31 12:56:58 +0200 (Thu, 31 May 2012) $
|
12
|
*/
|
13
|
class ModLanguage {
|
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
|
20
|
private $_sCurrentLanguage = '';
|
21
|
// @var string full directory with trailing slash to search language files in
|
22
|
private $_sLanguageDirectory = '';
|
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
|
29
|
private $_bLoaded = false;
|
30
|
// @object hold the Singleton instance
|
31
|
private static $_oInstance = null;
|
32
|
|
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
|
/**
|
42
|
* get a valid instance of this class
|
43
|
* @return object
|
44
|
*/
|
45
|
static public function getInstance() {
|
46
|
if( is_null(self::$_oInstance) ) {
|
47
|
$c = __CLASS__;
|
48
|
self::$_oInstance = new $c;
|
49
|
}
|
50
|
return self::$_oInstance;
|
51
|
}
|
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
|
/**
|
82
|
* set language and load needed language file
|
83
|
* @param string $sDirectory full path to the language files
|
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]
|
88
|
*/
|
89
|
public function setLanguage($sDirectory, $sCurrentLanguage, $sDefaultLanguage = 'EN')
|
90
|
{
|
91
|
// sanitize arguments
|
92
|
$sBasePath = realpath(dirname(dirname(__FILE__)));
|
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))) {
|
128
|
$msg = 'unable to find valid language definition file in<br />';
|
129
|
$msg .= '"'.str_replace($sBasePath, '', $this->_sLanguageDirectory).'"';
|
130
|
throw new TranslationException($msg);
|
131
|
}
|
132
|
$this->_bLoaded = true;
|
133
|
}else {
|
134
|
throw new SecDirectoryTraversalException($sLangDir);
|
135
|
}
|
136
|
}
|
137
|
/**
|
138
|
* load language from given directory
|
139
|
* @param string $sLangDir
|
140
|
* @param string $sLanguage
|
141
|
*/
|
142
|
private function _loadLanguage($sLangDir, $sLanguage)
|
143
|
{
|
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
|
}
|
149
|
}
|
150
|
/**
|
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
|
154
|
*/
|
155
|
private function _findFirstLanguage($sLangDir)
|
156
|
{
|
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;
|
167
|
}
|
168
|
}
|
169
|
}
|
170
|
return $sRetval;
|
171
|
}
|
172
|
/**
|
173
|
* import key-values from language file
|
174
|
* @param string $sLanguageFile
|
175
|
* @return array of language definitions
|
176
|
*/
|
177
|
private function _importArrays($sLanguageFile)
|
178
|
{
|
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
|
}
|
189
|
foreach($aLangSections as $sSection) {
|
190
|
// walk through all arrays
|
191
|
foreach(${$sSection} as $key => $value) {
|
192
|
// and import all found translations
|
193
|
$aLanguageTable[$sSection.'_'.$key] = $value;
|
194
|
}
|
195
|
}
|
196
|
return $aLanguageTable;
|
197
|
}
|
198
|
} // end class Translate
|
199
|
/**
|
200
|
* Exception class for Translation
|
201
|
*/
|
202
|
class TranslationException extends AppException {}
|