19 * @license GNU General Public License |
19 * @license GNU General Public License |
20 */ |
20 */ |
21 |
21 |
22 class Language |
22 class Language |
23 { |
23 { |
24 |
24 |
25 /** |
25 /** |
26 * The numerical ID of the loaded language. |
26 * The numerical ID of the loaded language. |
27 * @var int |
27 * @var int |
28 */ |
28 */ |
29 |
29 |
30 var $lang_id; |
30 var $lang_id; |
31 |
31 |
32 /** |
32 /** |
33 * The ISO-639-3 code for the loaded language. This should be grabbed directly from the database. |
33 * The ISO-639-3 code for the loaded language. This should be grabbed directly from the database. |
34 * @var string |
34 * @var string |
35 */ |
35 */ |
36 |
36 |
37 var $lang_code; |
37 var $lang_code; |
38 |
38 |
39 /** |
39 /** |
40 * Used to track when a language was last changed, to allow browsers to cache language data |
40 * Used to track when a language was last changed, to allow browsers to cache language data |
41 * @var int |
41 * @var int |
42 */ |
42 */ |
43 |
43 |
44 var $lang_timestamp; |
44 var $lang_timestamp; |
45 |
45 |
46 /** |
46 /** |
47 * Will be an object that holds an instance of the class configured with the site's default language. Only instanciated when needed. |
47 * Will be an object that holds an instance of the class configured with the site's default language. Only instanciated when needed. |
48 * @var object |
48 * @var object |
49 */ |
49 */ |
50 |
50 |
51 var $default; |
51 var $default; |
52 |
52 |
53 /** |
53 /** |
54 * The list of loaded strings. |
54 * The list of loaded strings. |
55 * @var array |
55 * @var array |
56 * @access private |
56 * @access private |
57 */ |
57 */ |
58 |
58 |
59 var $strings = array(); |
59 var $strings = array(); |
60 |
60 |
61 /** |
61 /** |
62 * Switch for debug mode. If true, will show an asterisk after localized strings. This |
62 * Switch for debug mode. If true, will show an asterisk after localized strings. This |
63 * can be useful if you're localizing a component and need to see what's already done. |
63 * can be useful if you're localizing a component and need to see what's already done. |
64 * @var bool |
64 * @var bool |
65 */ |
65 */ |
66 |
66 |
67 var $debug = false; |
67 var $debug = false; |
68 |
68 |
69 /** |
69 /** |
70 * List of available filters to pass variables through. |
70 * List of available filters to pass variables through. |
71 * @var array |
71 * @var array |
72 * @access private |
72 * @access private |
73 */ |
73 */ |
74 |
74 |
75 protected $filters = array(); |
75 protected $filters = array(); |
76 |
76 |
77 /** |
77 /** |
78 * Constructor. |
78 * Constructor. |
79 * @param int|string Language ID or code to load. |
79 * @param int|string Language ID or code to load. |
80 */ |
80 */ |
81 |
81 |
82 function __construct($lang) |
82 function __construct($lang) |
83 { |
83 { |
84 global $db, $session, $paths, $template, $plugins; // Common objects |
84 global $db, $session, $paths, $template, $plugins; // Common objects |
85 |
85 |
86 if ( defined('IN_ENANO_INSTALL') && ( !defined('ENANO_CONFIG_FETCHED') || ( defined('IN_ENANO_UPGRADE') && !defined('IN_ENANO_UPGRADE_POST') ) ) ) |
86 if ( defined('IN_ENANO_INSTALL') && ( !defined('ENANO_CONFIG_FETCHED') || ( defined('IN_ENANO_UPGRADE') && !defined('IN_ENANO_UPGRADE_POST') ) ) ) |
87 { |
87 { |
88 // special case for the Enano installer: it will load its own strings from a JSON file and just use this API for fetching |
88 // special case for the Enano installer: it will load its own strings from a JSON file and just use this API for fetching |
89 // and templatizing them. |
89 // and templatizing them. |
90 // 1.1.4 fix: this was still being called after main API startup from installer payload |
90 // 1.1.4 fix: this was still being called after main API startup from installer payload |
91 $this->lang_id = 1; |
91 $this->lang_id = 1; |
92 $this->lang_code = $lang; |
92 $this->lang_code = $lang; |
93 return true; |
93 return true; |
94 } |
94 } |
95 if ( is_string($lang) ) |
95 if ( is_string($lang) ) |
96 { |
96 { |
97 $sql_col = 'lang_code=\'' . $db->escape($lang) . '\''; |
97 $sql_col = 'lang_code=\'' . $db->escape($lang) . '\''; |
98 } |
98 } |
99 else if ( is_int($lang) ) |
99 else if ( is_int($lang) ) |
100 { |
100 { |
101 $sql_col = 'lang_id=' . $lang . ''; |
101 $sql_col = 'lang_id=' . $lang . ''; |
102 } |
102 } |
103 else |
103 else |
104 { |
104 { |
105 $db->_die('lang.php - attempting to pass invalid value to constructor'); |
105 $db->_die('lang.php - attempting to pass invalid value to constructor'); |
106 } |
106 } |
107 |
107 |
108 $lang_default = ( $x = getConfig('default_language') ) ? intval($x) : '0'; |
108 $lang_default = ( $x = getConfig('default_language') ) ? intval($x) : '0'; |
109 |
109 |
110 $q = $db->sql_query("SELECT lang_id, lang_code, last_changed, ( lang_id = $lang_default ) AS is_default FROM " . table_prefix . "language WHERE $sql_col OR lang_id = $lang_default ORDER BY is_default ASC LIMIT 1;"); |
110 $q = $db->sql_query("SELECT lang_id, lang_code, last_changed, ( lang_id = $lang_default ) AS is_default FROM " . table_prefix . "language WHERE $sql_col OR lang_id = $lang_default ORDER BY is_default ASC LIMIT 1;"); |
111 |
111 |
112 if ( !$q ) |
112 if ( !$q ) |
113 $db->_die('lang.php - main select query'); |
113 $db->_die('lang.php - main select query'); |
114 |
114 |
115 if ( $db->numrows() < 1 ) |
115 if ( $db->numrows() < 1 ) |
116 $db->_die('lang.php - There are no languages installed'); |
116 $db->_die('lang.php - There are no languages installed'); |
117 |
117 |
118 $row = $db->fetchrow(); |
118 $row = $db->fetchrow(); |
119 |
119 |
120 $this->lang_id = intval( $row['lang_id'] ); |
120 $this->lang_id = intval( $row['lang_id'] ); |
121 $this->lang_code = $row['lang_code']; |
121 $this->lang_code = $row['lang_code']; |
122 $this->lang_timestamp = $row['last_changed']; |
122 $this->lang_timestamp = $row['last_changed']; |
123 |
123 |
124 $this->register_filter('htmlsafe', 'htmlspecialchars'); |
124 $this->register_filter('htmlsafe', 'htmlspecialchars'); |
125 $this->register_filter('urlencode', 'urlencode'); |
125 $this->register_filter('urlencode', 'urlencode'); |
126 $this->register_filter('rawurlencode', 'rawurlencode'); |
126 $this->register_filter('rawurlencode', 'rawurlencode'); |
127 |
127 |
128 $code = $plugins->setHook('lang_init'); |
128 $code = $plugins->setHook('lang_init'); |
129 foreach ( $code as $cmd ) |
129 foreach ( $code as $cmd ) |
130 { |
130 { |
131 eval($cmd); |
131 eval($cmd); |
132 } |
132 } |
133 } |
133 } |
134 |
134 |
135 /** |
135 /** |
136 * Fetches language strings from the database, or a cache file if it's available. |
136 * Fetches language strings from the database, or a cache file if it's available. |
137 * @param bool If true (default), allows the cache to be used. |
137 * @param bool If true (default), allows the cache to be used. |
138 */ |
138 */ |
139 |
139 |
140 function fetch($allow_cache = true) |
140 function fetch($allow_cache = true) |
141 { |
141 { |
142 global $db, $session, $paths, $template, $plugins; // Common objects |
142 global $db, $session, $paths, $template, $plugins; // Common objects |
143 |
143 |
144 // Attempt to load the strings from a cache file |
144 // Attempt to load the strings from a cache file |
145 $loaded = false; |
145 $loaded = false; |
146 |
146 |
147 if ( $allow_cache ) |
147 if ( $allow_cache ) |
148 { |
148 { |
149 // Load the cache manager |
149 // Load the cache manager |
150 global $cache; |
150 global $cache; |
151 |
151 |
152 if ( $cached = $cache->fetch("lang_{$this->lang_id}") ) |
152 if ( $cached = $cache->fetch("lang_{$this->lang_id}") ) |
153 { |
153 { |
154 $this->merge($cached); |
154 $this->merge($cached); |
155 $loaded = true; |
155 $loaded = true; |
156 } |
156 } |
157 } |
157 } |
158 if ( !$loaded ) |
158 if ( !$loaded ) |
159 { |
159 { |
160 // No cache file - select and retrieve from the database |
160 // No cache file - select and retrieve from the database |
161 $q = $db->sql_unbuffered_query("SELECT string_category, string_name, string_content FROM " . table_prefix . "language_strings WHERE lang_id = {$this->lang_id};"); |
161 $q = $db->sql_unbuffered_query("SELECT string_category, string_name, string_content FROM " . table_prefix . "language_strings WHERE lang_id = {$this->lang_id};"); |
162 if ( !$q ) |
162 if ( !$q ) |
163 $db->_die('lang.php - selecting language string data'); |
163 $db->_die('lang.php - selecting language string data'); |
164 if ( $row = $db->fetchrow() ) |
164 if ( $row = $db->fetchrow() ) |
165 { |
165 { |
166 $strings = array(); |
166 $strings = array(); |
167 do |
167 do |
168 { |
168 { |
169 $cat =& $row['string_category']; |
169 $cat =& $row['string_category']; |
170 if ( !is_array(@$strings[$cat]) ) |
170 if ( !is_array(@$strings[$cat]) ) |
171 { |
171 { |
172 $strings[$cat] = array(); |
172 $strings[$cat] = array(); |
173 } |
173 } |
174 $strings[$cat][ $row['string_name'] ] = $row['string_content']; |
174 $strings[$cat][ $row['string_name'] ] = $row['string_content']; |
175 } |
175 } |
176 while ( $row = $db->fetchrow() ); |
176 while ( $row = $db->fetchrow() ); |
177 // all done fetching |
177 // all done fetching |
178 $this->merge($strings); |
178 $this->merge($strings); |
179 $this->regen_caches(false); |
179 $this->regen_caches(false); |
180 } |
180 } |
181 /* |
181 /* |
182 else |
182 else |
183 { |
183 { |
184 if ( !defined('ENANO_ALLOW_LOAD_NOLANG') ) |
184 if ( !defined('ENANO_ALLOW_LOAD_NOLANG') ) |
185 $db->_die('lang.php - No strings for language ' . $this->lang_code); |
185 $db->_die('lang.php - No strings for language ' . $this->lang_code); |
186 } |
186 } |
187 */ |
187 */ |
188 } |
188 } |
189 } |
189 } |
190 |
190 |
191 /** |
191 /** |
192 * Loads a file from the disk cache (treated as PHP) and merges it into RAM. |
192 * Loads a file from the disk cache (treated as PHP) and merges it into RAM. |
193 * @param string File to load |
193 * @param string File to load |
194 */ |
194 */ |
195 |
195 |
196 function load_cache_file($file) |
196 function load_cache_file($file) |
197 { |
197 { |
198 global $db, $session, $paths, $template, $plugins; // Common objects |
198 global $db, $session, $paths, $template, $plugins; // Common objects |
199 |
199 |
200 if ( !file_exists($file) ) |
200 if ( !file_exists($file) ) |
201 $db->_die('lang.php - requested cache file doesn\'t exist'); |
201 $db->_die('lang.php - requested cache file doesn\'t exist'); |
202 |
202 |
203 @include($file); |
203 @include($file); |
204 |
204 |
205 if ( !isset($lang_cache) || ( isset($lang_cache) && !is_array($lang_cache) ) ) |
205 if ( !isset($lang_cache) || ( isset($lang_cache) && !is_array($lang_cache) ) ) |
206 $db->_die('lang.php - the cache file is invalid (didn\'t set $lang_cache as an array)'); |
206 $db->_die('lang.php - the cache file is invalid (didn\'t set $lang_cache as an array)'); |
207 |
207 |
208 $this->merge($lang_cache); |
208 $this->merge($lang_cache); |
209 } |
209 } |
210 |
210 |
211 /** |
211 /** |
212 * Loads a JSON language file and parses the strings into RAM. Will use the cache if possible, but stays far away from the database, |
212 * Loads a JSON language file and parses the strings into RAM. Will use the cache if possible, but stays far away from the database, |
213 * which we assume doesn't exist yet. |
213 * which we assume doesn't exist yet. |
214 */ |
214 */ |
215 |
215 |
216 function load_file($file) |
216 function load_file($file) |
217 { |
217 { |
218 global $db, $session, $paths, $template, $plugins; // Common objects |
218 global $db, $session, $paths, $template, $plugins; // Common objects |
219 |
219 |
220 if ( !file_exists($file) ) |
220 if ( !file_exists($file) ) |
221 { |
221 { |
222 if ( defined('IN_ENANO_INSTALL') ) |
222 if ( defined('IN_ENANO_INSTALL') ) |
223 { |
223 { |
224 die('lang.php - requested JSON file (' . htmlspecialchars($file) . ') doesn\'t exist'); |
224 die('lang.php - requested JSON file (' . htmlspecialchars($file) . ') doesn\'t exist'); |
225 } |
225 } |
226 else |
226 else |
227 { |
227 { |
228 $db->_die('lang.php - requested JSON file doesn\'t exist'); |
228 $db->_die('lang.php - requested JSON file doesn\'t exist'); |
229 } |
229 } |
230 } |
230 } |
231 |
231 |
232 $contents = trim(@file_get_contents($file)); |
232 $contents = trim(@file_get_contents($file)); |
233 if ( empty($contents) ) |
233 if ( empty($contents) ) |
234 $db->_die('lang.php - empty language file...'); |
234 $db->_die('lang.php - empty language file...'); |
235 |
235 |
236 // Trim off all text before and after the starting and ending braces |
236 // Trim off all text before and after the starting and ending braces |
237 $contents = preg_replace('/^([^{]+)\{/', '{', $contents); |
237 $contents = preg_replace('/^([^{]+)\{/', '{', $contents); |
238 $contents = preg_replace('/\}([^}]+)$/', '}', $contents); |
238 $contents = preg_replace('/\}([^}]+)$/', '}', $contents); |
239 $contents = trim($contents); |
239 $contents = trim($contents); |
240 |
240 |
241 if ( empty($contents) ) |
241 if ( empty($contents) ) |
242 $db->_die('lang.php - no meat to the language file...'); |
242 $db->_die('lang.php - no meat to the language file...'); |
243 |
243 |
244 $checksum = md5($contents); |
244 $checksum = md5($contents); |
245 if ( file_exists("./cache/lang_json_{$checksum}.php") ) |
245 if ( file_exists("./cache/lang_json_{$checksum}.php") ) |
246 { |
246 { |
247 $this->load_cache_file("./cache/lang_json_{$checksum}.php"); |
247 $this->load_cache_file("./cache/lang_json_{$checksum}.php"); |
248 } |
248 } |
249 else |
249 else |
250 { |
250 { |
251 // Correct syntax to be nice to the json parser |
251 // Correct syntax to be nice to the json parser |
252 |
252 |
253 // eliminate comments |
253 // eliminate comments |
254 $contents = preg_replace(array( |
254 $contents = preg_replace(array( |
255 // eliminate single line comments in '// ...' form |
255 // eliminate single line comments in '// ...' form |
256 '#^\s*//(.+)$#m', |
256 '#^\s*//(.+)$#m', |
257 // eliminate multi-line comments in '/* ... */' form, at start of string |
257 // eliminate multi-line comments in '/* ... */' form, at start of string |
258 '#^\s*/\*(.+)\*/#Us', |
258 '#^\s*/\*(.+)\*/#Us', |
259 // eliminate multi-line comments in '/* ... */' form, at end of string |
259 // eliminate multi-line comments in '/* ... */' form, at end of string |
260 '#/\*(.+)\*/\s*$#Us' |
260 '#/\*(.+)\*/\s*$#Us' |
261 ), '', $contents); |
261 ), '', $contents); |
262 |
262 |
263 $contents = preg_replace('/([,\{\[])([\s]*?)([a-z0-9_]+)([\s]*?):/', '\\1\\2"\\3" :', $contents); |
263 $contents = preg_replace('/([,\{\[])([\s]*?)([a-z0-9_]+)([\s]*?):/', '\\1\\2"\\3" :', $contents); |
264 |
264 |
265 try |
265 try |
266 { |
266 { |
267 $langdata = enano_json_decode($contents); |
267 $langdata = enano_json_decode($contents); |
268 } |
268 } |
269 catch(Zend_Json_Exception $e) |
269 catch(Zend_Json_Exception $e) |
270 { |
270 { |
271 $db->_die('lang.php - Exception caught by JSON parser</p><pre>' . htmlspecialchars(print_r($e, true)) . '</pre><p>'); |
271 $db->_die('lang.php - Exception caught by JSON parser</p><pre>' . htmlspecialchars(print_r($e, true)) . '</pre><p>'); |
272 exit; |
272 exit; |
273 } |
273 } |
274 |
274 |
275 if ( !is_array($langdata) ) |
275 if ( !is_array($langdata) ) |
276 $db->_die('lang.php - invalid language file'); |
276 $db->_die('lang.php - invalid language file'); |
277 |
277 |
278 if ( !isset($langdata['categories']) || !isset($langdata['strings']) ) |
278 if ( !isset($langdata['categories']) || !isset($langdata['strings']) ) |
279 $db->_die('lang.php - language file does not contain the proper items'); |
279 $db->_die('lang.php - language file does not contain the proper items'); |
280 |
280 |
281 $this->merge($langdata['strings']); |
281 $this->merge($langdata['strings']); |
282 |
282 |
283 $lang_file = "./cache/lang_json_{$checksum}.php"; |
283 $lang_file = "./cache/lang_json_{$checksum}.php"; |
284 |
284 |
285 $handle = @fopen($lang_file, 'w'); |
285 $handle = @fopen($lang_file, 'w'); |
286 if ( !$handle ) |
286 if ( !$handle ) |
287 // Couldn't open the file. Silently fail and let the strings come from RAM. |
287 // Couldn't open the file. Silently fail and let the strings come from RAM. |
288 return false; |
288 return false; |
289 |
289 |
290 // The file's open, that means we should be good. |
290 // The file's open, that means we should be good. |
291 fwrite($handle, '<?php |
291 fwrite($handle, '<?php |
292 // This file was generated automatically by Enano. You should not edit this file because any changes you make |
292 // This file was generated automatically by Enano. You should not edit this file because any changes you make |
293 // to it will not be visible in the ACP and all changes will be lost upon any changes to strings in the admin panel. |
293 // to it will not be visible in the ACP and all changes will be lost upon any changes to strings in the admin panel. |
294 |
294 |
295 $lang_cache = '); |
295 $lang_cache = '); |
296 |
296 |
297 $exported = $this->var_export_string($this->strings); |
297 $exported = $this->var_export_string($this->strings); |
298 if ( empty($exported) ) |
298 if ( empty($exported) ) |
299 // Ehh, that's not good |
299 // Ehh, that's not good |
300 $db->_die('lang.php - load_file(): var_export_string() failed'); |
300 $db->_die('lang.php - load_file(): var_export_string() failed'); |
301 |
301 |
302 fwrite($handle, $exported . '; ?>'); |
302 fwrite($handle, $exported . '; ?>'); |
303 |
303 |
304 // Clean up |
304 // Clean up |
305 unset($exported, $langdata); |
305 unset($exported, $langdata); |
306 |
306 |
307 // Done =) |
307 // Done =) |
308 fclose($handle); |
308 fclose($handle); |
309 } |
309 } |
310 } |
310 } |
311 |
311 |
312 /** |
312 /** |
313 * Merges a standard language assoc array ($arr[cat][stringid]) with the master in RAM. |
313 * Merges a standard language assoc array ($arr[cat][stringid]) with the master in RAM. |
314 * @param array |
314 * @param array |
315 */ |
315 */ |
316 |
316 |
317 function merge($strings) |
317 function merge($strings) |
318 { |
318 { |
319 // This is stupidly simple. |
319 // This is stupidly simple. |
320 foreach ( $strings as $cat_id => $contents ) |
320 foreach ( $strings as $cat_id => $contents ) |
321 { |
321 { |
322 if ( !isset($this->strings[$cat_id]) || ( isset($this->strings[$cat_id]) && !is_array($this->strings[$cat_id]) ) ) |
322 if ( !isset($this->strings[$cat_id]) || ( isset($this->strings[$cat_id]) && !is_array($this->strings[$cat_id]) ) ) |
323 $this->strings[$cat_id] = array(); |
323 $this->strings[$cat_id] = array(); |
324 foreach ( $contents as $string_id => $string ) |
324 foreach ( $contents as $string_id => $string ) |
325 { |
325 { |
326 $this->strings[$cat_id][$string_id] = $string; |
326 $this->strings[$cat_id][$string_id] = $string; |
327 } |
327 } |
328 } |
328 } |
329 } |
329 } |
330 |
330 |
331 /** |
331 /** |
332 * Imports a JSON-format language file into the database and merges with current strings. |
332 * Imports a JSON-format language file into the database and merges with current strings. |
333 * @param string Path to the JSON file to load |
333 * @param string Path to the JSON file to load |
334 * @param bool If true, only imports new strings and skips those that already exist. Defaults to false (import all strings) |
334 * @param bool If true, only imports new strings and skips those that already exist. Defaults to false (import all strings) |
335 * @param bool Enable debugging output, makes the process over CLI more interesting |
335 * @param bool Enable debugging output, makes the process over CLI more interesting |
336 */ |
336 */ |
337 |
337 |
338 function import($file, $skip_existing = false, $debug = false) |
338 function import($file, $skip_existing = false, $debug = false) |
339 { |
339 { |
340 global $db, $session, $paths, $template, $plugins; // Common objects |
340 global $db, $session, $paths, $template, $plugins; // Common objects |
341 |
341 |
342 if ( !file_exists($file) ) |
342 if ( !file_exists($file) ) |
343 $db->_die('lang.php - can\'t import language file: string file doesn\'t exist'); |
343 $db->_die('lang.php - can\'t import language file: string file doesn\'t exist'); |
344 |
344 |
345 if ( $this->lang_id == 0 ) |
345 if ( $this->lang_id == 0 ) |
346 $db->_die('lang.php - BUG: trying to perform import when $lang->lang_id == 0'); |
346 $db->_die('lang.php - BUG: trying to perform import when $lang->lang_id == 0'); |
347 |
347 |
348 if ( $debug ) |
348 if ( $debug ) |
349 $br = ( isset($_SERVER['REQUEST_URI']) ) ? '<br />' : ''; |
349 $br = ( isset($_SERVER['REQUEST_URI']) ) ? '<br />' : ''; |
350 |
350 |
351 if ( $debug ) |
351 if ( $debug ) |
352 echo "Importing file: $file$br\n Checking file...$br\n"; |
352 echo "Importing file: $file$br\n Checking file...$br\n"; |
353 |
353 |
354 $contents = trim(@file_get_contents($file)); |
354 $contents = trim(@file_get_contents($file)); |
355 |
355 |
356 if ( empty($contents) ) |
356 if ( empty($contents) ) |
357 $db->_die('lang.php - can\'t load the contents of the language file'); |
357 $db->_die('lang.php - can\'t load the contents of the language file'); |
358 |
358 |
359 if ( $debug ) |
359 if ( $debug ) |
360 echo " Cleaning up JSON$br\n"; |
360 echo " Cleaning up JSON$br\n"; |
361 |
361 |
362 // Trim off all text before and after the starting and ending braces |
362 // Trim off all text before and after the starting and ending braces |
363 $contents = preg_replace('/^([^{]+)\{/', '{', $contents); |
363 $contents = preg_replace('/^([^{]+)\{/', '{', $contents); |
364 $contents = preg_replace('/\}([^}]+)$/', '}', $contents); |
364 $contents = preg_replace('/\}([^}]+)$/', '}', $contents); |
365 |
365 |
366 // Correct syntax to be nice to the json parser |
366 // Correct syntax to be nice to the json parser |
367 $contents = enano_clean_json($contents); |
367 $contents = enano_clean_json($contents); |
368 |
368 |
369 if ( $debug ) |
369 if ( $debug ) |
370 echo " Decoding JSON stream$br\n"; |
370 echo " Decoding JSON stream$br\n"; |
371 |
371 |
372 try |
372 try |
373 { |
373 { |
374 $langdata = enano_json_decode($contents); |
374 $langdata = enano_json_decode($contents); |
375 } |
375 } |
376 catch(Zend_Json_Exception $e) |
376 catch(Zend_Json_Exception $e) |
377 { |
377 { |
378 $db->_die('lang.php - Exception caught by JSON parser</p><pre>' . htmlspecialchars(print_r($e, true)) . '</pre><p>'); |
378 $db->_die('lang.php - Exception caught by JSON parser</p><pre>' . htmlspecialchars(print_r($e, true)) . '</pre><p>'); |
379 exit; |
379 exit; |
380 } |
380 } |
381 |
381 |
382 if ( !is_array($langdata) ) |
382 if ( !is_array($langdata) ) |
383 { |
383 { |
384 $db->_die('lang.php - invalid or non-well-formed language file'); |
384 $db->_die('lang.php - invalid or non-well-formed language file'); |
385 } |
385 } |
386 |
386 |
387 if ( $debug ) |
387 if ( $debug ) |
388 echo " Starting string import$br\n"; |
388 echo " Starting string import$br\n"; |
389 |
389 |
390 return $this->import_array($langdata, $skip_existing, $debug); |
390 return $this->import_array($langdata, $skip_existing, $debug); |
391 } |
391 } |
392 |
392 |
393 /** |
393 /** |
394 * Imports a JSON-format language file into the database and merges with current strings. |
394 * Imports a JSON-format language file into the database and merges with current strings. |
395 * @param string Path to plugin file |
395 * @param string Path to plugin file |
396 */ |
396 */ |
397 |
397 |
398 function import_plugin($file) |
398 function import_plugin($file) |
399 { |
399 { |
400 global $db, $session, $paths, $template, $plugins; // Common objects |
400 global $db, $session, $paths, $template, $plugins; // Common objects |
401 |
401 |
402 if ( !file_exists($file) ) |
402 if ( !file_exists($file) ) |
403 $db->_die('lang.php - can\'t import language file: string file doesn\'t exist'); |
403 $db->_die('lang.php - can\'t import language file: string file doesn\'t exist'); |
404 |
404 |
405 if ( $this->lang_id == 0 ) |
405 if ( $this->lang_id == 0 ) |
406 $db->_die('lang.php - BUG: trying to perform import when $lang->lang_id == 0'); |
406 $db->_die('lang.php - BUG: trying to perform import when $lang->lang_id == 0'); |
407 |
407 |
408 $block = pluginLoader::parse_plugin_blocks($file, 'language'); |
408 $block = pluginLoader::parse_plugin_blocks($file, 'language'); |
409 if ( !is_array($block) ) |
409 if ( !is_array($block) ) |
410 return false; |
410 return false; |
411 if ( !isset($block[0]) ) |
411 if ( !isset($block[0]) ) |
412 return false; |
412 return false; |
413 |
413 |
414 $contents =& $block[0]['value']; |
414 $contents =& $block[0]['value']; |
415 |
415 |
416 // Trim off all text before and after the starting and ending braces |
416 // Trim off all text before and after the starting and ending braces |
417 $contents = enano_trim_json($contents); |
417 $contents = enano_trim_json($contents); |
418 |
418 |
419 // Correct syntax to be nice to the json parser |
419 // Correct syntax to be nice to the json parser |
420 $contents = enano_clean_json($contents); |
420 $contents = enano_clean_json($contents); |
421 |
421 |
422 try |
422 try |
423 { |
423 { |
424 $langdata = enano_json_decode($contents); |
424 $langdata = enano_json_decode($contents); |
425 } |
425 } |
426 catch(Zend_Json_Exception $e) |
426 catch(Zend_Json_Exception $e) |
427 { |
427 { |
428 $db->_die('lang.php - Exception caught by JSON parser</p><pre>' . htmlspecialchars(print_r($e, true)) . '</pre><p>'); |
428 $db->_die('lang.php - Exception caught by JSON parser</p><pre>' . htmlspecialchars(print_r($e, true)) . '</pre><p>'); |
429 exit; |
429 exit; |
430 } |
430 } |
431 |
431 |
432 if ( !is_array($langdata) ) |
432 if ( !is_array($langdata) ) |
433 { |
433 { |
434 $db->_die('lang.php - invalid or non-well-formed language file'); |
434 $db->_die('lang.php - invalid or non-well-formed language file'); |
435 } |
435 } |
436 |
436 |
437 // Does the plugin support the current language? |
437 // Does the plugin support the current language? |
438 if ( isset($langdata[$this->lang_code]) ) |
438 if ( isset($langdata[$this->lang_code]) ) |
439 { |
439 { |
440 // Yes, import that |
440 // Yes, import that |
441 return $this->import_array($langdata[$this->lang_code]); |
441 return $this->import_array($langdata[$this->lang_code]); |
442 } |
442 } |
443 |
443 |
444 // Just import the first language we run across. |
444 // Just import the first language we run across. |
445 $supported_langs = array_keys($langdata); |
445 $supported_langs = array_keys($langdata); |
446 |
446 |
447 if ( !isset($supported_langs[0]) ) |
447 if ( !isset($supported_langs[0]) ) |
448 { |
448 { |
449 $db->_die('lang.php - plugin has an invalid or corrupt language block'); |
449 $db->_die('lang.php - plugin has an invalid or corrupt language block'); |
450 } |
450 } |
451 |
451 |
452 $first_lang = $supported_langs[0]; |
452 $first_lang = $supported_langs[0]; |
453 |
453 |
454 return $this->import_array($langdata[$first_lang], false, true); |
454 return $this->import_array($langdata[$first_lang], false, true); |
455 } |
455 } |
456 |
456 |
457 /** |
457 /** |
458 * Performs the actual import of string data. |
458 * Performs the actual import of string data. |
459 * @param array Parsed JSON object, should be in the form of an array |
459 * @param array Parsed JSON object, should be in the form of an array |
460 * @param bool If true, only imports new strings and skips those that already exist. Defaults to false. |
460 * @param bool If true, only imports new strings and skips those that already exist. Defaults to false. |
461 * @param bool Enable debugging output |
461 * @param bool Enable debugging output |
462 * @access private |
462 * @access private |
463 */ |
463 */ |
464 |
464 |
465 protected function import_array($langdata, $skip_existing = false, $debug = false) |
465 protected function import_array($langdata, $skip_existing = false, $debug = false) |
466 { |
466 { |
467 global $db, $session, $paths, $template, $plugins; // Common objects |
467 global $db, $session, $paths, $template, $plugins; // Common objects |
468 |
468 |
469 if ( !isset($langdata['categories']) || !isset($langdata['strings']) ) |
469 if ( !isset($langdata['categories']) || !isset($langdata['strings']) ) |
470 $db->_die('lang.php - language file does not contain the proper items'); |
470 $db->_die('lang.php - language file does not contain the proper items'); |
471 |
471 |
472 if ( $debug ) |
472 if ( $debug ) |
473 $br = ( isset($_SERVER['REQUEST_URI']) ) ? '<br />' : ''; |
473 $br = ( isset($_SERVER['REQUEST_URI']) ) ? '<br />' : ''; |
474 |
474 |
475 $insert_list = array(); |
475 $insert_list = array(); |
476 $delete_list = array(); |
476 $delete_list = array(); |
477 |
477 |
478 foreach ( $langdata['categories'] as $category ) |
478 foreach ( $langdata['categories'] as $category ) |
479 { |
479 { |
480 if ( isset($langdata['strings'][$category]) ) |
480 if ( isset($langdata['strings'][$category]) ) |
481 { |
481 { |
482 if ( $debug ) |
482 if ( $debug ) |
483 { |
483 { |
484 $desc = ( isset($langdata['strings']['meta'][$category]) ) ? $langdata['strings']['meta'][$category] : $this->get("meta_$category"); |
484 $desc = ( isset($langdata['strings']['meta'][$category]) ) ? $langdata['strings']['meta'][$category] : $this->get("meta_$category"); |
485 echo " Indexing category: $category ({$desc})$br\n"; |
485 echo " Indexing category: $category ({$desc})$br\n"; |
486 } |
486 } |
487 foreach ( $langdata['strings'][$category] as $string_name => $string_value ) |
487 foreach ( $langdata['strings'][$category] as $string_name => $string_value ) |
488 { |
488 { |
489 // should we skip this string? |
489 // should we skip this string? |
490 if ( isset($this->strings[$category]) && $skip_existing ) |
490 if ( isset($this->strings[$category]) && $skip_existing ) |
491 { |
491 { |
492 if ( isset($this->strings[$category][$string_name]) ) |
492 if ( isset($this->strings[$category][$string_name]) ) |
493 { |
493 { |
494 // already exists, skip |
494 // already exists, skip |
495 if ( $debug ) |
495 if ( $debug ) |
496 echo " Skipping string (already exists): {$category}_{$string_name}$br\n"; |
496 echo " Skipping string (already exists): {$category}_{$string_name}$br\n"; |
497 continue; |
497 continue; |
498 } |
498 } |
499 } |
499 } |
500 $string_name = $db->escape($string_name); |
500 $string_name = $db->escape($string_name); |
501 $string_value = $db->escape($string_value); |
501 $string_value = $db->escape($string_value); |
502 $category_name = $db->escape($category); |
502 $category_name = $db->escape($category); |
503 $insert_list[] = "({$this->lang_id}, '$category_name', '$string_name', '$string_value')"; |
503 $insert_list[] = "({$this->lang_id}, '$category_name', '$string_name', '$string_value')"; |
504 $delete_list[] = "( lang_id = {$this->lang_id} AND string_category = '$category_name' AND string_name = '$string_name' )"; |
504 $delete_list[] = "( lang_id = {$this->lang_id} AND string_category = '$category_name' AND string_name = '$string_name' )"; |
505 } |
505 } |
506 } |
506 } |
507 } |
507 } |
508 |
508 |
509 if ( $debug ) |
509 if ( $debug ) |
510 { |
510 { |
511 echo " Running deletion of old strings..."; |
511 echo " Running deletion of old strings..."; |
512 $start = microtime_float(); |
512 $start = microtime_float(); |
513 } |
513 } |
514 $delete_list = implode(" OR\n ", $delete_list); |
514 $delete_list = implode(" OR\n ", $delete_list); |
515 |
515 |
516 if ( !empty($delete_list) ) |
516 if ( !empty($delete_list) ) |
517 { |
517 { |
518 $sql = "DELETE FROM " . table_prefix . "language_strings WHERE $delete_list;"; |
518 $sql = "DELETE FROM " . table_prefix . "language_strings WHERE $delete_list;"; |
519 |
519 |
520 // Free some memory |
520 // Free some memory |
521 unset($delete_list); |
521 unset($delete_list); |
522 |
522 |
523 // Run the query |
523 // Run the query |
524 $q = $db->sql_query($sql); |
524 $q = $db->sql_query($sql); |
525 if ( !$q ) |
525 if ( !$q ) |
526 $db->_die('lang.php - couldn\'t kill off them old strings'); |
526 $db->_die('lang.php - couldn\'t kill off them old strings'); |
527 } |
527 } |
528 |
528 |
529 if ( $debug ) |
529 if ( $debug ) |
530 { |
530 { |
531 $time = round(microtime_float() - $start, 5); |
531 $time = round(microtime_float() - $start, 5); |
532 echo "({$time}s)$br\n"; |
532 echo "({$time}s)$br\n"; |
533 } |
533 } |
534 |
534 |
535 if ( !empty($insert_list) ) |
535 if ( !empty($insert_list) ) |
536 { |
536 { |
537 if ( $debug ) |
537 if ( $debug ) |
538 { |
538 { |
539 echo " Inserting strings..."; |
539 echo " Inserting strings..."; |
540 $start = microtime_float(); |
540 $start = microtime_float(); |
541 } |
541 } |
542 $insert_list = implode(",\n ", $insert_list); |
542 $insert_list = implode(",\n ", $insert_list); |
543 $sql = "INSERT INTO " . table_prefix . "language_strings(lang_id, string_category, string_name, string_content) VALUES\n $insert_list;"; |
543 $sql = "INSERT INTO " . table_prefix . "language_strings(lang_id, string_category, string_name, string_content) VALUES\n $insert_list;"; |
544 |
544 |
545 // Free some memory |
545 // Free some memory |
546 unset($insert_list); |
546 unset($insert_list); |
547 |
547 |
548 // Run the query |
548 // Run the query |
549 $q = $db->sql_query($sql); |
549 $q = $db->sql_query($sql); |
550 if ( !$q ) |
550 if ( !$q ) |
551 $db->_die('lang.php - couldn\'t insert strings in import()'); |
551 $db->_die('lang.php - couldn\'t insert strings in import()'); |
552 |
552 |
553 if ( $debug ) |
553 if ( $debug ) |
554 { |
554 { |
555 $time = round(microtime_float() - $start, 5); |
555 $time = round(microtime_float() - $start, 5); |
556 echo "({$time}s)$br\n"; |
556 echo "({$time}s)$br\n"; |
557 } |
557 } |
558 } |
558 } |
559 |
559 |
560 // YAY! done! |
560 // YAY! done! |
561 // This will regenerate the cache file if possible. |
561 // This will regenerate the cache file if possible. |
562 if ( $debug ) |
562 if ( $debug ) |
563 echo " Regenerating cache file$br\n"; |
563 echo " Regenerating cache file$br\n"; |
564 $this->regen_caches(); |
564 $this->regen_caches(); |
565 |
565 |
566 return true; |
566 return true; |
567 } |
567 } |
568 |
568 |
569 /** |
569 /** |
570 * Refetches the strings and writes out the cache file. |
570 * Refetches the strings and writes out the cache file. |
571 */ |
571 */ |
572 |
572 |
573 function regen_caches($refetch = true) |
573 function regen_caches($refetch = true) |
574 { |
574 { |
575 global $db, $session, $paths, $template, $plugins; // Common objects |
575 global $db, $session, $paths, $template, $plugins; // Common objects |
576 |
576 |
577 // Refresh the strings in RAM to the latest copies in the DB |
577 // Refresh the strings in RAM to the latest copies in the DB |
578 if ( $refetch ) |
578 if ( $refetch ) |
579 $this->fetch(false); |
579 $this->fetch(false); |
580 |
580 |
581 // Load the cache manager |
581 // Load the cache manager |
582 global $cache; |
582 global $cache; |
583 |
583 |
584 // Store it |
584 // Store it |
585 $cache->store("lang_{$this->lang_id}", $this->strings, -1); |
585 $cache->store("lang_{$this->lang_id}", $this->strings, -1); |
586 |
586 |
587 // Update timestamp in database |
587 // Update timestamp in database |
588 $q = $db->sql_query('UPDATE ' . table_prefix . 'language SET last_changed = ' . time() . ' WHERE lang_id = ' . $this->lang_id . ';'); |
588 $q = $db->sql_query('UPDATE ' . table_prefix . 'language SET last_changed = ' . time() . ' WHERE lang_id = ' . $this->lang_id . ';'); |
589 if ( !$q ) |
589 if ( !$q ) |
590 $db->_die('lang.php - updating timestamp on language'); |
590 $db->_die('lang.php - updating timestamp on language'); |
591 |
591 |
592 return true; |
592 return true; |
593 } |
593 } |
594 |
594 |
595 /** |
595 /** |
596 * Calls var_export() on whatever, and returns the function's output. |
596 * Calls var_export() on whatever, and returns the function's output. |
597 * @param mixed Whatever you want var_exported. Usually an array. |
597 * @param mixed Whatever you want var_exported. Usually an array. |
598 * @return string |
598 * @return string |
599 */ |
599 */ |
600 |
600 |
601 static function var_export_string($val) |
601 static function var_export_string($val) |
602 { |
602 { |
603 ob_start(); |
603 ob_start(); |
604 var_export($val); |
604 var_export($val); |
605 $contents = ob_get_contents(); |
605 $contents = ob_get_contents(); |
606 ob_end_clean(); |
606 ob_end_clean(); |
607 return $contents; |
607 return $contents; |
608 } |
608 } |
609 |
609 |
610 /** |
610 /** |
611 * Registers a filter, a function that strings can be passed through to change the string somehow (e.g. htmlspecialchars) |
611 * Registers a filter, a function that strings can be passed through to change the string somehow (e.g. htmlspecialchars) |
612 * @param string Filter name. Lowercase alphanumeric (htmlsafe) |
612 * @param string Filter name. Lowercase alphanumeric (htmlsafe) |
613 * @param callback Function to call. |
613 * @param callback Function to call. |
614 * @return bool True on success, false if some error occurred |
614 * @return bool True on success, false if some error occurred |
615 */ |
615 */ |
616 |
616 |
617 public function register_filter($filter_name, $filter_function) |
617 public function register_filter($filter_name, $filter_function) |
618 { |
618 { |
619 if ( !is_string($filter_function) && !is_array($filter_function) ) |
619 if ( !is_string($filter_function) && !is_array($filter_function) ) |
620 { |
620 { |
621 return false; |
621 return false; |
622 } |
622 } |
623 if ( ( is_string($filter_function) && !function_exists($filter_function) ) || ( is_array($filter_function) && !method_exists(@$filter_function[0], @$filter_function[1]) ) ) |
623 if ( ( is_string($filter_function) && !function_exists($filter_function) ) || ( is_array($filter_function) && !method_exists(@$filter_function[0], @$filter_function[1]) ) ) |
624 { |
624 { |
625 return false; |
625 return false; |
626 } |
626 } |
627 if ( !preg_match('/^[a-z0-9_]+$/', $filter_name) ) |
627 if ( !preg_match('/^[a-z0-9_]+$/', $filter_name) ) |
628 { |
628 { |
629 return false; |
629 return false; |
630 } |
630 } |
631 $this->filters[$filter_name] = $filter_function; |
631 $this->filters[$filter_name] = $filter_function; |
632 return true; |
632 return true; |
633 } |
633 } |
634 |
634 |
635 /** |
635 /** |
636 * Fetches a language string from the cache in RAM. If it isn't there, it will call fetch() again and then try. If it still can't find it, it will ask for the string |
636 * Fetches a language string from the cache in RAM. If it isn't there, it will call fetch() again and then try. If it still can't find it, it will ask for the string |
637 * in the default language. If even then the string can't be found, this function will return what was passed to it. |
637 * in the default language. If even then the string can't be found, this function will return what was passed to it. |
638 * |
638 * |
639 * This will also templatize strings. If a string contains variables in the format %foo%, you may specify the second parameter as an associative array in the format |
639 * This will also templatize strings. If a string contains variables in the format %foo%, you may specify the second parameter as an associative array in the format |
640 * of 'foo' => 'foo substitute'. |
640 * of 'foo' => 'foo substitute'. |
641 * |
641 * |
642 * @param string ID of the string to fetch. This will always be in the format of category_stringid. |
642 * @param string ID of the string to fetch. This will always be in the format of category_stringid. |
643 * @param array Optional. Associative array of substitutions. |
643 * @param array Optional. Associative array of substitutions. |
644 * @return string |
644 * @return string |
645 */ |
645 */ |
646 |
646 |
647 function get($string_id, $substitutions = false) |
647 function get($string_id, $substitutions = false) |
648 { |
648 { |
649 if ( !is_array($substitutions) ) |
649 if ( !is_array($substitutions) ) |
650 $substitutions = array(); |
650 $substitutions = array(); |
651 // if this isn't a valid language string ID, just return the string unprocessed. |
651 // if this isn't a valid language string ID, just return the string unprocessed. |
652 if ( !preg_match('/^([a-z0-9]+)((_[a-z0-9]+)+)$/', $string_id) ) |
652 if ( !preg_match('/^([a-z0-9]+)((_[a-z0-9]+)+)$/', $string_id) ) |
653 return $string_id; |
653 return $string_id; |
654 return $this->substitute($this->get_uncensored($string_id), $substitutions); |
654 return $this->substitute($this->get_uncensored($string_id), $substitutions); |
655 } |
655 } |
656 |
656 |
657 /** |
657 /** |
658 * The same as get(), but does not perform any substitution or filtering. Used in get() (of course) and in the admin panel, where |
658 * The same as get(), but does not perform any substitution or filtering. Used in get() (of course) and in the admin panel, where |
659 * strings are updated only if they were changed. |
659 * strings are updated only if they were changed. |
660 * |
660 * |
661 * @param string ID of the string to fetch. This will always be in the format of category_stringid. |
661 * @param string ID of the string to fetch. This will always be in the format of category_stringid. |
662 * @param array Optional. Associative array of substitutions. |
662 * @param array Optional. Associative array of substitutions. |
663 * @return string |
663 * @return string |
664 */ |
664 */ |
665 |
665 |
666 function get_uncensored($string_id, $substitutions = false) |
666 function get_uncensored($string_id, $substitutions = false) |
667 { |
667 { |
668 global $db, $session, $paths, $template, $plugins; // Common objects |
668 global $db, $session, $paths, $template, $plugins; // Common objects |
669 |
669 |
670 // Extract the category and string ID |
670 // Extract the category and string ID |
671 $category = substr($string_id, 0, ( strpos($string_id, '_') )); |
671 $category = substr($string_id, 0, ( strpos($string_id, '_') )); |
672 $string_name = substr($string_id, ( strpos($string_id, '_') + 1 )); |
672 $string_name = substr($string_id, ( strpos($string_id, '_') + 1 )); |
673 $found = false; |
673 $found = false; |
674 if ( isset($this->strings[$category]) && isset($this->strings[$category][$string_name]) ) |
674 if ( isset($this->strings[$category]) && isset($this->strings[$category][$string_name]) ) |
675 { |
675 { |
676 $found = true; |
676 $found = true; |
677 $string = $this->strings[$category][$string_name]; |
677 $string = $this->strings[$category][$string_name]; |
678 } |
678 } |
679 if ( !$found ) |
679 if ( !$found ) |
680 { |
680 { |
681 // Ehh, the string wasn't found. Rerun fetch() and try again. |
681 // Ehh, the string wasn't found. Rerun fetch() and try again. |
682 // Or if it's the installer, no use in refetching, so just fail. |
682 // Or if it's the installer, no use in refetching, so just fail. |
683 if ( defined('IN_ENANO_INSTALL') || ( defined('ENANO_INSTALLED') && !@$db->_conn ) ) |
683 if ( defined('IN_ENANO_INSTALL') || ( defined('ENANO_INSTALLED') && !@$db->_conn ) ) |
684 { |
684 { |
685 return $string_id; |
685 return $string_id; |
686 } |
686 } |
687 $this->fetch(); |
687 $this->fetch(); |
688 profiler_log('Language(' . $this->lang_code . '): refetched due to missing string: ' . $string_id); |
688 profiler_log('Language(' . $this->lang_code . '): refetched due to missing string: ' . $string_id); |
689 if ( isset($this->strings[$category]) && isset($this->strings[$category][$string_name]) ) |
689 if ( isset($this->strings[$category]) && isset($this->strings[$category][$string_name]) ) |
690 { |
690 { |
691 $found = true; |
691 $found = true; |
692 $string = $this->strings[$category][$string_name]; |
692 $string = $this->strings[$category][$string_name]; |
693 } |
693 } |
694 if ( !$found ) |
694 if ( !$found ) |
695 { |
695 { |
696 // STILL not found. Check the default language. |
696 // STILL not found. Check the default language. |
697 $lang_default = ( $x = getConfig('default_language') ) ? intval($x) : $this->lang_id; |
697 $lang_default = ( $x = getConfig('default_language') ) ? intval($x) : $this->lang_id; |
698 if ( $lang_default != $this->lang_id ) |
698 if ( $lang_default != $this->lang_id ) |
699 { |
699 { |
700 if ( !is_object($this->default) ) |
700 if ( !is_object($this->default) ) |
701 $this->default = new Language($lang_default); |
701 $this->default = new Language($lang_default); |
702 return $this->default->get_uncensored($string_id); |
702 return $this->default->get_uncensored($string_id); |
703 } |
703 } |
704 } |
704 } |
705 } |
705 } |
706 if ( !$found ) |
706 if ( !$found ) |
707 { |
707 { |
708 // Alright, it's nowhere. Return the input, grumble grumble... |
708 // Alright, it's nowhere. Return the input, grumble grumble... |
709 return $string_id; |
709 return $string_id; |
710 } |
710 } |
711 // Found it! |
711 // Found it! |
712 return $string; |
712 return $string; |
713 } |
713 } |
714 |
714 |
715 /** |
715 /** |
716 * Processes substitutions. |
716 * Processes substitutions. |
717 * @param string |
717 * @param string |
718 * @param array |
718 * @param array |
719 * @return string |
719 * @return string |
720 */ |
720 */ |
721 |
721 |
722 function substitute($string, $subs) |
722 function substitute($string, $subs) |
723 { |
723 { |
724 preg_match_all('/%this\.([a-z0-9_]+)((?:\|(?:[a-z0-9_]+))*)%/', $string, $matches); |
724 preg_match_all('/%this\.([a-z0-9_]+)((?:\|(?:[a-z0-9_]+))*)%/', $string, $matches); |
725 if ( count($matches[0]) > 0 ) |
725 if ( count($matches[0]) > 0 ) |
726 { |
726 { |
727 foreach ( $matches[1] as $i => $string_id ) |
727 foreach ( $matches[1] as $i => $string_id ) |
728 { |
728 { |
729 $result = $this->get($string_id); |
729 $result = $this->get($string_id); |
730 $string = str_replace($matches[0][$i], $this->process_filters($result, $matches[2][$i]), $string); |
730 $string = str_replace($matches[0][$i], $this->process_filters($result, $matches[2][$i]), $string); |
731 } |
731 } |
732 } |
732 } |
733 preg_match_all('/%config\.([a-z0-9_]+)((?:\|(?:[a-z0-9_]+))*)%/', $string, $matches); |
733 preg_match_all('/%config\.([a-z0-9_]+)((?:\|(?:[a-z0-9_]+))*)%/', $string, $matches); |
734 if ( count($matches[0]) > 0 ) |
734 if ( count($matches[0]) > 0 ) |
735 { |
735 { |
736 foreach ( $matches[1] as $i => $string_id ) |
736 foreach ( $matches[1] as $i => $string_id ) |
737 { |
737 { |
738 $result = getConfig($string_id, ''); |
738 $result = getConfig($string_id, ''); |
739 $string = str_replace($matches[0][$i], $this->process_filters($result, $matches[2][$i]), $string); |
739 $string = str_replace($matches[0][$i], $this->process_filters($result, $matches[2][$i]), $string); |
740 } |
740 } |
741 } |
741 } |
742 preg_match_all('/%([a-z0-9_]+)((?:\|(?:[a-z0-9_]+))*)%/', $string, $matches); |
742 preg_match_all('/%([a-z0-9_]+)((?:\|(?:[a-z0-9_]+))*)%/', $string, $matches); |
743 if ( count($matches[0]) > 0 ) |
743 if ( count($matches[0]) > 0 ) |
744 { |
744 { |
745 foreach ( $matches[1] as $i => $string_id ) |
745 foreach ( $matches[1] as $i => $string_id ) |
746 { |
746 { |
747 if ( isset($subs[$string_id]) ) |
747 if ( isset($subs[$string_id]) ) |
748 { |
748 { |
749 $string = str_replace($matches[0][$i], $this->process_filters($subs[$string_id], $matches[2][$i]), $string); |
749 $string = str_replace($matches[0][$i], $this->process_filters($subs[$string_id], $matches[2][$i]), $string); |
750 } |
750 } |
751 } |
751 } |
752 } |
752 } |
753 return ( $this->debug ) ? "$string*" : $string; |
753 return ( $this->debug ) ? "$string*" : $string; |
754 } |
754 } |
755 |
755 |
756 /** |
756 /** |
757 * Processes filters to a language string. |
757 * Processes filters to a language string. |
758 * @param string Unprocessed string |
758 * @param string Unprocessed string |
759 * @param string Filter list (format: |filter1|filter2|filter3, initial pipe is important); can also be an array if you so desire |
759 * @param string Filter list (format: |filter1|filter2|filter3, initial pipe is important); can also be an array if you so desire |
760 * @return string |
760 * @return string |
761 */ |
761 */ |
762 |
762 |
763 function process_filters($string, $filters) |
763 function process_filters($string, $filters) |
764 { |
764 { |
765 if ( !empty($filters) ) |
765 if ( !empty($filters) ) |
766 { |
766 { |
767 $filters = trim($filters, '|'); |
767 $filters = trim($filters, '|'); |
768 $filters = explode('|', $filters); |
768 $filters = explode('|', $filters); |
769 foreach ( $filters as $filter ) |
769 foreach ( $filters as $filter ) |
770 { |
770 { |
771 if ( isset($this->filters[$filter]) ) |
771 if ( isset($this->filters[$filter]) ) |
772 { |
772 { |
773 $result = call_user_func($this->filters[$filter], $string); |
773 $result = call_user_func($this->filters[$filter], $string); |
774 if ( is_string($result) ) |
774 if ( is_string($result) ) |
775 { |
775 { |
776 $string = $result; |
776 $string = $result; |
777 } |
777 } |
778 } |
778 } |
779 } |
779 } |
780 } |
780 } |
781 return $string; |
781 return $string; |
782 } |
782 } |
783 |
783 |
784 } // class Language |
784 } // class Language |
785 |
785 |
786 ?> |
786 ?> |