831 |
florian |
1 |
<?php
|
|
|
2 |
|
|
|
3 |
////////////////////////////////////////////////////////////////////////////////
|
|
|
4 |
// //
|
|
|
5 |
// Copyright (C) 2006 Phorum Development Team //
|
|
|
6 |
// http://www.phorum.org //
|
|
|
7 |
// //
|
|
|
8 |
// This program is free software. You can redistribute it and/or modify //
|
|
|
9 |
// it under the terms of either the current Phorum License (viewable at //
|
|
|
10 |
// phorum.org) or the Phorum License that was distributed with this file //
|
|
|
11 |
// //
|
|
|
12 |
// This program is distributed in the hope that it will be useful, //
|
|
|
13 |
// but WITHOUT ANY WARRANTY, without even the implied warranty of //
|
|
|
14 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. //
|
|
|
15 |
// //
|
|
|
16 |
// You should have received a copy of the Phorum License //
|
|
|
17 |
// along with this program. //
|
|
|
18 |
////////////////////////////////////////////////////////////////////////////////
|
|
|
19 |
|
|
|
20 |
// TODO have a better way to differentiate between Phorum distribution
|
|
|
21 |
// TODO and addon files, so we son't index text strings from addon
|
|
|
22 |
// TODO files in here.
|
|
|
23 |
|
|
|
24 |
if(!defined("PHORUM_ADMIN")) return;
|
|
|
25 |
|
|
|
26 |
define('TOKEN_DEBUGGER', 0);
|
|
|
27 |
|
|
|
28 |
// Because sometimes the script can take a while, we set the
|
|
|
29 |
// PHP time limit to a high value to prevent execution timeouts.
|
|
|
30 |
set_time_limit(600);
|
|
|
31 |
|
|
|
32 |
include_once "./include/admin/PhorumInputForm.php";
|
|
|
33 |
|
|
|
34 |
// Get some form variables.
|
|
|
35 |
$action = isset($_POST['action']) ? $_POST['action'] : 'start';
|
|
|
36 |
$language = isset($_POST['language']) ? $_POST['language'] : $PHORUM["SETTINGS"]["default_language"];
|
|
|
37 |
$filename = isset($_POST['filename']) ? trim($_POST['filename']) : '';
|
|
|
38 |
$displayname = isset($_POST['displayname']) ? trim($_POST['displayname']) : '';
|
|
|
39 |
|
|
|
40 |
// Handle downloading a new language file.
|
|
|
41 |
if ($action == 'download_lang')
|
|
|
42 |
{
|
|
|
43 |
// Ditch HTML header we have so far (from the admin framework).
|
|
|
44 |
ob_end_clean();
|
|
|
45 |
|
|
|
46 |
// Send the new languagefile to the client.
|
|
|
47 |
$basename = preg_replace('/-.*$/', '', $filename);
|
|
|
48 |
$fullfile = $basename . '-' . PHORUM . '.php';
|
|
|
49 |
header ("Content-Type: application/download; filename=$fullfile");
|
|
|
50 |
header ("Content-Disposition: attachment; filename=\"$fullfile\"");
|
|
|
51 |
$langfile = phorum_cache_get('updated_language', $filename);
|
|
|
52 |
print $langfile;
|
|
|
53 |
|
|
|
54 |
exit();
|
|
|
55 |
}
|
|
|
56 |
|
|
|
57 |
// Handle updating a language.
|
|
|
58 |
if ($action == 'update_lang') {
|
|
|
59 |
$langinfo = phorum_get_language_info();
|
|
|
60 |
return phorum_generate_language_file($language, $langinfo[$language], false);
|
|
|
61 |
}
|
|
|
62 |
|
|
|
63 |
// Handle generating a new language.
|
|
|
64 |
if ($action == 'generate_lang') {
|
|
|
65 |
$filename = preg_replace('/\.php$/i', '', basename($filename));
|
|
|
66 |
if ($filename == '') {
|
|
|
67 |
phorum_admin_error("The basename may not be empty");
|
|
|
68 |
} elseif (! preg_match('/^[\w_\.]+$/', $filename)) {
|
|
|
69 |
phorum_admin_error(
|
|
|
70 |
"The basename contains illegal characters. Please, keep the " .
|
|
|
71 |
"filename simple by using only letters, numbers, underscores and " .
|
|
|
72 |
"dots. You can't use hyphens, because those are used for " .
|
|
|
73 |
"separating the basename from the Phorum version for which the " .
|
|
|
74 |
"language file is used."
|
|
|
75 |
);
|
|
|
76 |
} elseif ($displayname == '') {
|
|
|
77 |
phorum_admin_error("The display name for the language may not be empty.");
|
|
|
78 |
} else {
|
|
|
79 |
$filename .= "-" . PHORUM;
|
|
|
80 |
return phorum_generate_language_file($filename, $displayname, true);
|
|
|
81 |
}
|
|
|
82 |
}
|
|
|
83 |
|
|
|
84 |
|
|
|
85 |
// Handle start page.
|
|
|
86 |
$frm = new PhorumInputForm ("", "post", "Generate updated language file");
|
|
|
87 |
|
|
|
88 |
$frm->addmessage(<<<INTRO
|
|
|
89 |
<font color="red">EXPERIMENTAL FEATURE<br/>
|
|
|
90 |
Please backup your existing language file if you replace it with
|
|
|
91 |
one generated by this maintenance tool. We feel pretty confident
|
|
|
92 |
about it, but we wouldn't want you to loose data in case of bugs.</font>
|
|
|
93 |
<hr size="0"/>
|
|
|
94 |
|
|
|
95 |
<h2>Manage language files</h2>
|
|
|
96 |
This is a tool which can be used for easy maintenance of
|
|
|
97 |
language files for Phorum. It will collect all actual used
|
|
|
98 |
language strings from the Phorum software and generate an
|
|
|
99 |
updated langage file for your language of choice based on
|
|
|
100 |
those strings. In the generated language file, missing and
|
|
|
101 |
deprecated strings will be clearly marked, so you can
|
|
|
102 |
update the language file to match the running Phorum distribution.
|
|
|
103 |
INTRO
|
|
|
104 |
);
|
|
|
105 |
|
|
|
106 |
$frm->hidden("module", "manage_languages");
|
|
|
107 |
$frm->hidden("action", "update_lang");
|
|
|
108 |
$frm->addbreak("Update existing language file");
|
|
|
109 |
$frm->addrow("Generate updated version of an existing language file",
|
|
|
110 |
$frm->select_tag("language", phorum_get_language_info(), $language, 0));
|
|
|
111 |
$frm->show();
|
|
|
112 |
|
|
|
113 |
|
|
|
114 |
$frm = new PhorumInputForm("", "post", "Generate new language file");
|
|
|
115 |
$frm->addmessage(<<<INTRO
|
|
|
116 |
In case there is no language file available for your language or
|
|
|
117 |
if you want to create a new language file all of your own, you can
|
|
|
118 |
generate a new language file using the form below.
|
|
|
119 |
INTRO
|
|
|
120 |
);
|
|
|
121 |
|
|
|
122 |
$frm->hidden("module", "manage_languages");
|
|
|
123 |
$frm->hidden("action", "generate_lang");
|
|
|
124 |
$frm->addbreak("Generate a new language file");
|
|
|
125 |
$frm->addrow("The basename for the generated file", $frm->text_box('filename', $filename, 20));
|
|
|
126 |
$frm->addrow("The display name for the language", $frm->text_box('displayname', $displayname, 20));
|
|
|
127 |
$frm->show();
|
|
|
128 |
|
|
|
129 |
exit;
|
|
|
130 |
|
|
|
131 |
|
|
|
132 |
// ======================================================================
|
|
|
133 |
// Generating language files
|
|
|
134 |
// ======================================================================
|
|
|
135 |
|
|
|
136 |
function phorum_generate_language_file($lang, $displayname, $generate_new)
|
|
|
137 |
{
|
|
|
138 |
global $fullfile;
|
|
|
139 |
|
|
|
140 |
$basename = preg_replace('/-.*$/', '', $lang);
|
|
|
141 |
$fullfile = $basename . '-' . PHORUM . '.php';
|
|
|
142 |
|
|
|
143 |
// Get our default language file.
|
|
|
144 |
$DEFAULT = phorum_get_language('english');
|
|
|
145 |
|
|
|
146 |
// Get the languagefile to update, unless generating a new language.
|
|
|
147 |
$CURRENT = array();
|
|
|
148 |
if (! $generate_new) {
|
|
|
149 |
$CURRENT = phorum_get_language($lang);
|
|
|
150 |
} else {
|
|
|
151 |
$CURRENT['STORE']['language_hide'] = 0;
|
|
|
152 |
$CURRENT['STORE']['language'] = urlencode("'" . addslashes($displayname) . "'");
|
|
|
153 |
}
|
|
|
154 |
|
|
|
155 |
// Keep a copy of the languagefile.
|
|
|
156 |
$CURRENT_COPY = $CURRENT;
|
|
|
157 |
|
|
|
158 |
// Collect all language strings from the distribution files.
|
|
|
159 |
$language_strings = phorum_extract_language_strings();
|
|
|
160 |
|
|
|
161 |
$frm = new PhorumInputForm ("", "post", "Download new " . htmlspecialchars($fullfile) . " language file");
|
|
|
162 |
$frm->hidden("module", "manage_languages");
|
|
|
163 |
$frm->hidden("action", "download_lang");
|
|
|
164 |
$frm->hidden("filename", $lang);
|
|
|
165 |
|
|
|
166 |
if (! $generate_new) {
|
|
|
167 |
|
|
|
168 |
$frm->addmessage(
|
|
|
169 |
"<h2>Update language: " . htmlspecialchars($displayname) . "</h2>" .
|
|
|
170 |
"Below you will see all the things that have been updated " .
|
|
|
171 |
"to get to the new version of the language file. At the " .
|
|
|
172 |
"bottom of the page you will find a download button to download " .
|
|
|
173 |
"the updated language file. This language file has to be placed " .
|
|
|
174 |
"in <b>include/lang/" . htmlspecialchars($lang) . ".php</b> to make it " .
|
|
|
175 |
"available to Phorum (backup your old file first of course!). " .
|
|
|
176 |
"If new language strings have been added, " .
|
|
|
177 |
"they will be marked with '***' in the language file, so it's " .
|
|
|
178 |
"easy for you to find them."
|
|
|
179 |
);
|
|
|
180 |
$frm->addbreak("Updates for the new language file");
|
|
|
181 |
} else {
|
|
|
182 |
$frm->addmessage(
|
|
|
183 |
"<h2>Generate new language: " . htmlspecialchars($displayname) . "</h2>" .
|
|
|
184 |
"A new language file has been generated. Below you will find " .
|
|
|
185 |
"a download button to download the new file. In this file, you " .
|
|
|
186 |
"can replace all language strings by strings which apply to " .
|
|
|
187 |
"\"" . htmlspecialchars($displayname) . "\". After updating the new " .
|
|
|
188 |
"file, you will have to place it in " .
|
|
|
189 |
"<b>include/lang/" . htmlspecialchars($fullfile) . ".php</b>, " .
|
|
|
190 |
"so Phorum can use it (backup your old file first of course!)."
|
|
|
191 |
);
|
|
|
192 |
}
|
|
|
193 |
|
|
|
194 |
$notifies = 0;
|
|
|
195 |
|
|
|
196 |
// Check for language strings that are missing.
|
|
|
197 |
$missing = array();
|
|
|
198 |
$count_missing = 0;
|
|
|
199 |
foreach ($language_strings as $string => $data) {
|
|
|
200 |
if ($string == 'TIME') continue; // This one is special.
|
|
|
201 |
if (! isset($CURRENT["DATA"]["LANG"][$string])) {
|
|
|
202 |
array_push($missing, $string);
|
|
|
203 |
$translation = urlencode("'" . addslashes($string) . "'");
|
|
|
204 |
if (isset($DEFAULT["DATA"]["LANG"][$string])) {
|
|
|
205 |
$translation = $DEFAULT["DATA"]["LANG"][$string];
|
|
|
206 |
}
|
|
|
207 |
$CURRENT_COPY["DATA"]["LANG"][$string] =
|
|
|
208 |
urlencode("'***'. " . urldecode($translation));
|
|
|
209 |
|
|
|
210 |
$count_missing++;
|
|
|
211 |
if (! $generate_new) {
|
|
|
212 |
$frm->addrow("MISSING ($count_missing)", $string);
|
|
|
213 |
$notifies++;
|
|
|
214 |
}
|
|
|
215 |
} else {
|
|
|
216 |
unset($CURRENT["DATA"]["LANG"][$string]);
|
|
|
217 |
}
|
|
|
218 |
}
|
|
|
219 |
|
|
|
220 |
// Check for language strings that are deprecated.
|
|
|
221 |
$deprecated = array();
|
|
|
222 |
$count_deprecated = 0;
|
|
|
223 |
if (! $generate_new)
|
|
|
224 |
{
|
|
|
225 |
foreach ($CURRENT["DATA"]["LANG"] as $string => $translation)
|
|
|
226 |
{
|
|
|
227 |
if ($string == 'TIME') continue; // This one is special.
|
|
|
228 |
|
|
|
229 |
$count_deprecated++;
|
|
|
230 |
$deprecated[$string] = true;
|
|
|
231 |
|
|
|
232 |
// Only notify the deprecation if not already in deprecated state.
|
|
|
233 |
if (! isset($CURRENT['STORE']['DEPRECATED'][$string])) {
|
|
|
234 |
$frm->addrow("DEPRECATED ($count_deprecated)", htmlspecialchars($string));
|
|
|
235 |
$notifies++;
|
|
|
236 |
}
|
|
|
237 |
}
|
|
|
238 |
}
|
|
|
239 |
$CURRENT_COPY['STORE']['DEPRECATED'] = $deprecated;
|
|
|
240 |
|
|
|
241 |
// Restore our full current language data from the copy.
|
|
|
242 |
$CURRENT = $CURRENT_COPY;
|
|
|
243 |
|
|
|
244 |
// Copy values from our default language to the current language.
|
|
|
245 |
$copyfields = array('long_date', 'short_date', 'locale');
|
|
|
246 |
foreach ($copyfields as $f) {
|
|
|
247 |
if (! isset($CURRENT[$f])) {
|
|
|
248 |
$CURRENT[$f] = $DEFAULT[$f];
|
|
|
249 |
if (! $generate_new) {
|
|
|
250 |
$frm->addrow("MISSING VARIABLE", "$f set to default " .
|
|
|
251 |
htmlentities(urldecode($DEFAULT[$f])));
|
|
|
252 |
$notifies++;
|
|
|
253 |
}
|
|
|
254 |
}
|
|
|
255 |
}
|
|
|
256 |
// Copy default values beneath DATA to the current language.
|
|
|
257 |
$datafields = array('CHARSET', 'MAILENCODING', 'LANG_META');
|
|
|
258 |
foreach ($datafields as $f) {
|
|
|
259 |
if (! isset($CURRENT['DATA'][$f]) || $CURRENT['DATA'][$f] == '') {
|
|
|
260 |
$CURRENT['DATA'][$f] = $DEFAULT['DATA'][$f];
|
|
|
261 |
if (! $generate_new) {
|
|
|
262 |
$frm->addrow("MISSING VARIABLE", "DATA->$f set to default " .
|
|
|
263 |
htmlentities(urldecode($DEFAULT['DATA'][$f])));
|
|
|
264 |
$notifies++;
|
|
|
265 |
}
|
|
|
266 |
}
|
|
|
267 |
}
|
|
|
268 |
|
|
|
269 |
// Copy default values for timezone information to the current language.
|
|
|
270 |
foreach ($DEFAULT['DATA']['LANG']['TIME'] as $key => $val) {
|
|
|
271 |
if (! isset($CURRENT['DATA']['LANG']['TIME'][$key])) {
|
|
|
272 |
$CURRENT['DATA']['LANG']['TIME'][$key] = $val;
|
|
|
273 |
|
|
|
274 |
if (! $generate_new) {
|
|
|
275 |
$dflt = htmlentities(urldecode($DEFAULT['DATA']['LANG']['TIME'][$key]));
|
|
|
276 |
$frm->addrow("MISSING TZINFO", "TZ $key set to default<br/>$dflt");
|
|
|
277 |
$notifies++;
|
|
|
278 |
}
|
|
|
279 |
}
|
|
|
280 |
}
|
|
|
281 |
|
|
|
282 |
if ($generate_new) {
|
|
|
283 |
$frm->addrow("COMPLETED", "A new language file has been generated for you");
|
|
|
284 |
} elseif (! $notifies) {
|
|
|
285 |
$frm->addrow("NONE", "There were no updates for the current \"$lang\" language file");
|
|
|
286 |
}
|
|
|
287 |
|
|
|
288 |
$frm->show();
|
|
|
289 |
|
|
|
290 |
phorum_write_language_file($lang, $CURRENT);
|
|
|
291 |
}
|
|
|
292 |
|
|
|
293 |
function phorum_write_language_file($lang, $CURRENT)
|
|
|
294 |
{
|
|
|
295 |
// Sort array keys.
|
|
|
296 |
ksort($CURRENT['DATA']['LANG']);
|
|
|
297 |
ksort($CURRENT['DATA']['STORE']['DEPRECATED']);
|
|
|
298 |
|
|
|
299 |
$langfile =
|
|
|
300 |
"<?php\n" .
|
|
|
301 |
"\n" .
|
|
|
302 |
$CURRENT['STORE']['keep_comment'] . "\n" .
|
|
|
303 |
"\n" .
|
|
|
304 |
"// ============================================================\n" .
|
|
|
305 |
"// General settings\n" .
|
|
|
306 |
"// ============================================================\n" .
|
|
|
307 |
"\n" .
|
|
|
308 |
"// The language name as it is presented in the interface.\n" .
|
|
|
309 |
"\$language = " . urldecode($CURRENT['STORE']['language']) . ";\n" .
|
|
|
310 |
"\n" .
|
|
|
311 |
"// Uncomment this to hide this language from the user-select-box.\n" .
|
|
|
312 |
($CURRENT['STORE']['language_hide'] ? '' : '//') . "\$language_hide = 1;\n" .
|
|
|
313 |
"\n" .
|
|
|
314 |
"// Date formatting. Check the PHP-docs for the syntax of these\n" .
|
|
|
315 |
"// entries (http://www.php.net/strftime). One tip: do not use\n" .
|
|
|
316 |
"// %T for showing the time zone, as users can change their time zone.\n" .
|
|
|
317 |
"\$PHORUM['long_date'] = " . urldecode($CURRENT['long_date']) . ";\n" .
|
|
|
318 |
"\$PHORUM['short_date'] = " . urldecode($CURRENT['short_date']) . ";\n" .
|
|
|
319 |
"\n" .
|
|
|
320 |
"// The locale setting for enabling localized times/dates. Take a look\n" .
|
|
|
321 |
"// at http://www.w3.org/WAI/ER/IG/ert/iso639.htm for the needed string.\n" .
|
|
|
322 |
"\$PHORUM['locale'] = " . urldecode($CURRENT['locale']) . ";\n" .
|
|
|
323 |
"\n" .
|
|
|
324 |
"// The character set to use for converting html into safe valid text.\n" .
|
|
|
325 |
"// Also used in the header template for the xml tag. For a list of\n" .
|
|
|
326 |
"// supported character sets see: http://www.php.net/htmlentities\n" .
|
|
|
327 |
"// You may also need to set a meta-tag with a character set in it.\n" .
|
|
|
328 |
"\$PHORUM['DATA']['CHARSET'] = " . urldecode($CURRENT['DATA']['CHARSET']) . ";\n" .
|
|
|
329 |
"\n" .
|
|
|
330 |
"// The encoding used for outgoing mail messages.\n" .
|
|
|
331 |
"\$PHORUM['DATA']['MAILENCODING'] = " . urldecode($CURRENT['DATA']['MAILENCODING']) . ";\n" .
|
|
|
332 |
"\n" .
|
|
|
333 |
"// Some languages need additional meta tags to set encoding, etc.\n" .
|
|
|
334 |
"\$PHORUM['DATA']['LANG_META'] = " . urldecode($CURRENT['DATA']['LANG_META']) . ";\n" .
|
|
|
335 |
"\n" .
|
|
|
336 |
"// ============================================================\n" .
|
|
|
337 |
"// Language translation strings\n" .
|
|
|
338 |
"// ============================================================\n" .
|
|
|
339 |
"\n" .
|
|
|
340 |
"\$PHORUM['DATA']['LANG'] = array(\n";
|
|
|
341 |
|
|
|
342 |
// Add active language data to the array.
|
|
|
343 |
foreach ($CURRENT['DATA']['LANG'] as $key => $val) {
|
|
|
344 |
if ($key == 'TIME') continue;
|
|
|
345 |
if (isset($CURRENT['STORE']['DEPRECATED'][$key])) continue;
|
|
|
346 |
|
|
|
347 |
$langfile .= " '$key' => " . urldecode($val) . ",\n";
|
|
|
348 |
}
|
|
|
349 |
|
|
|
350 |
// Add deprecated language data to the array.
|
|
|
351 |
if (count($CURRENT['STORE']['DEPRECATED']))
|
|
|
352 |
{
|
|
|
353 |
$langfile .=
|
|
|
354 |
"\n" .
|
|
|
355 |
" // ============================================================\n" .
|
|
|
356 |
" // DEPRECATED:\n" .
|
|
|
357 |
" // These are all language strings which are not used anymore.\n" .
|
|
|
358 |
" // You might want to keep them to make this language file work\n" .
|
|
|
359 |
" // for versions of Phorum prior to version " . PHORUM . "\n" .
|
|
|
360 |
" // ============================================================\n" .
|
|
|
361 |
"\n";
|
|
|
362 |
|
|
|
363 |
foreach ($CURRENT['STORE']['DEPRECATED'] as $key => $dummy) {
|
|
|
364 |
$langfile .= " '$key' => " . urldecode($CURRENT['DATA']['LANG'][$key]) . ",\n";
|
|
|
365 |
}
|
|
|
366 |
}
|
|
|
367 |
|
|
|
368 |
$langfile .=
|
|
|
369 |
");\n" .
|
|
|
370 |
"\n" .
|
|
|
371 |
"// ============================================================\n" .
|
|
|
372 |
"// Timezone description strings\n" .
|
|
|
373 |
"// ============================================================\n" .
|
|
|
374 |
"\n" .
|
|
|
375 |
"\$PHORUM['DATA']['LANG']['TIME'] = array(\n";
|
|
|
376 |
|
|
|
377 |
foreach ($CURRENT['DATA']['LANG']['TIME'] as $key => $val) {
|
|
|
378 |
$pre = sprintf(" %6s", "'$key'");
|
|
|
379 |
$langfile .= "$pre => " . urldecode($val) . ",\n";
|
|
|
380 |
}
|
|
|
381 |
|
|
|
382 |
$langfile .=
|
|
|
383 |
");\n" .
|
|
|
384 |
"\n" .
|
|
|
385 |
"?>\n";
|
|
|
386 |
|
|
|
387 |
phorum_cache_put('updated_language', $lang, $langfile);
|
|
|
388 |
}
|
|
|
389 |
|
|
|
390 |
|
|
|
391 |
// ======================================================================
|
|
|
392 |
// Parsing language files
|
|
|
393 |
// ======================================================================
|
|
|
394 |
|
|
|
395 |
// Helper function for phorum_get_language() to be able to do
|
|
|
396 |
// some debugging output while getting all PHP tokens.
|
|
|
397 |
function token_shift(&$tokens)
|
|
|
398 |
{
|
|
|
399 |
$token = array_shift($tokens);
|
|
|
400 |
if (TOKEN_DEBUGGER > 1) {
|
|
|
401 |
print '<div style="color: darkorange">';
|
|
|
402 |
if (is_array($token)) {
|
|
|
403 |
print "COMPLEX: " . token_name($token[0]) . " [" . htmlspecialchars($token[1]) . "]<br/>";
|
|
|
404 |
} else {
|
|
|
405 |
print "SIMPLE: [" . htmlspecialchars($token) . "]<br/>";
|
|
|
406 |
}
|
|
|
407 |
print '</div>';
|
|
|
408 |
}
|
|
|
409 |
return $token;
|
|
|
410 |
}
|
|
|
411 |
|
|
|
412 |
function token_skip_whitespace(&$tokens)
|
|
|
413 |
{
|
|
|
414 |
while ($tokens[0][0] == T_WHITESPACE) {
|
|
|
415 |
array_shift($tokens);
|
|
|
416 |
|
|
|
417 |
}
|
|
|
418 |
}
|
|
|
419 |
|
|
|
420 |
function token_get_string(&$tokens, $string = NULL)
|
|
|
421 |
{
|
|
|
422 |
$levels = 0;
|
|
|
423 |
|
|
|
424 |
while (count($tokens))
|
|
|
425 |
{
|
|
|
426 |
$token = token_shift($tokens);
|
|
|
427 |
|
|
|
428 |
if (is_array($token))
|
|
|
429 |
{
|
|
|
430 |
switch ($token[0])
|
|
|
431 |
{
|
|
|
432 |
case T_COMMENT:
|
|
|
433 |
if (strstr($token[1], 'DEPRECATED')) {
|
|
|
434 |
global $in_deprecated;
|
|
|
435 |
$in_deprecated = true;
|
|
|
436 |
}
|
|
|
437 |
break;
|
|
|
438 |
|
|
|
439 |
// Tokens which we handle in scalar token code.
|
|
|
440 |
case T_DOUBLE_ARROW:
|
|
|
441 |
$token = '=>';
|
|
|
442 |
break;
|
|
|
443 |
case T_CURLY_OPEN:
|
|
|
444 |
$token = '{';
|
|
|
445 |
break;
|
|
|
446 |
|
|
|
447 |
case T_WHITESPACE:
|
|
|
448 |
case T_ENCAPSED_AND_WHITESPACE:
|
|
|
449 |
case T_CONSTANT_ENCAPSED_STRING:
|
|
|
450 |
case T_NUM_STRING:
|
|
|
451 |
case T_STRING:
|
|
|
452 |
case T_ARRAY:
|
|
|
453 |
case T_LNUMBER:
|
|
|
454 |
case T_VARIABLE:
|
|
|
455 |
case T_CHARACTER:
|
|
|
456 |
$string .= $token[1];
|
|
|
457 |
break;
|
|
|
458 |
default:
|
|
|
459 |
die ("Unhandled complex " . token_name($token[0]) . " token in token_get_string: " .
|
|
|
460 |
htmlspecialchars($token[1]));
|
|
|
461 |
break;
|
|
|
462 |
}
|
|
|
463 |
}
|
|
|
464 |
|
|
|
465 |
if (is_scalar($token))
|
|
|
466 |
{
|
|
|
467 |
$oldlevels = $levels;
|
|
|
468 |
|
|
|
469 |
// Keep track of nested brackets and curlies.
|
|
|
470 |
if ($token == '(' || $token == '{' || $token == '[') {
|
|
|
471 |
$levels++;
|
|
|
472 |
} elseif ($levels && ($token == ')' || $token == '}' || $token == ']')) {
|
|
|
473 |
$levels--;
|
|
|
474 |
}
|
|
|
475 |
|
|
|
476 |
if ($levels || $oldlevels) {
|
|
|
477 |
$string .= $token;
|
|
|
478 |
} else {
|
|
|
479 |
// Tokens which end a string.
|
|
|
480 |
if ($token == ';' || $token == '=' ||
|
|
|
481 |
$token == '=>' || $token == ',' ||
|
|
|
482 |
$token == ')') {
|
|
|
483 |
$string = trim($string);
|
|
|
484 |
return array($string, $token);
|
|
|
485 |
} else {
|
|
|
486 |
$string .= $token;
|
|
|
487 |
}
|
|
|
488 |
}
|
|
|
489 |
}
|
|
|
490 |
}
|
|
|
491 |
}
|
|
|
492 |
|
|
|
493 |
// This function retrieves all info from a language file, by directly
|
|
|
494 |
// parsing its tokens. We can't simply load the language file, because
|
|
|
495 |
// we have to extract any PHP code intact from it. By loading, all
|
|
|
496 |
// PHP code would be interpreted.
|
|
|
497 |
function phorum_get_language($lang)
|
|
|
498 |
{
|
|
|
499 |
$path = "./include/lang/$lang.php";
|
|
|
500 |
$PHORUM = array();
|
|
|
501 |
$DEPRECATED = array();
|
|
|
502 |
$keep_comment = '';
|
|
|
503 |
if (! file_exists($path)) {
|
|
|
504 |
die("Cannot locate language module in $path");
|
|
|
505 |
}
|
|
|
506 |
|
|
|
507 |
// Read the language file. Keep track of comments that
|
|
|
508 |
// we want to keep (those starting with '##').
|
|
|
509 |
$file = '';
|
|
|
510 |
$fp = fopen($path, "r");
|
|
|
511 |
if (! $fp) die("Cannot read language file $path");
|
|
|
512 |
while (($line = fgets($fp))) {
|
|
|
513 |
$file .= $line;
|
|
|
514 |
if (substr($line, 0, 2) == '##') {
|
|
|
515 |
$keep_comment .= $line;
|
|
|
516 |
}
|
|
|
517 |
}
|
|
|
518 |
fclose($fp);
|
|
|
519 |
|
|
|
520 |
// Split the contents of the language file into PHP tokens.
|
|
|
521 |
$tokens = token_get_all($file);
|
|
|
522 |
|
|
|
523 |
// Parse the PHP tokens.
|
|
|
524 |
while (count($tokens))
|
|
|
525 |
{
|
|
|
526 |
// Extract all variables. The rest is ignored.
|
|
|
527 |
$token = token_shift($tokens);
|
|
|
528 |
if (is_array($token))
|
|
|
529 |
{
|
|
|
530 |
if ($token[0] == T_VARIABLE) {
|
|
|
531 |
list($varname,$endedby) = token_get_string($tokens, $token[1]);
|
|
|
532 |
if ($endedby != '=') break; // We want only the assignments.
|
|
|
533 |
|
|
|
534 |
// Peek at the following code, to see what type of variable we're
|
|
|
535 |
// handling. Scalar or array.
|
|
|
536 |
token_skip_whitespace($tokens);
|
|
|
537 |
if ($tokens[0][0] == T_ARRAY)
|
|
|
538 |
{
|
|
|
539 |
global $in_deprecated;
|
|
|
540 |
$in_deprecated = false;
|
|
|
541 |
|
|
|
542 |
// Handle opening bracket for the array.
|
|
|
543 |
token_shift($tokens);
|
|
|
544 |
token_skip_whitespace($tokens);
|
|
|
545 |
$token = token_shift($tokens);
|
|
|
546 |
if ($token != '(') {
|
|
|
547 |
die("$path: Expected array opening bracket for array " .
|
|
|
548 |
htmlspecialchars($varname));
|
|
|
549 |
}
|
|
|
550 |
|
|
|
551 |
while (count($tokens))
|
|
|
552 |
{
|
|
|
553 |
// Get key
|
|
|
554 |
list($key, $endedby) = token_get_string($tokens);
|
|
|
555 |
if ($endedby != '=>') {
|
|
|
556 |
die("$path: Expected double arrow (=>) for key " .
|
|
|
557 |
htmlspecialchars($key) . " in array " .
|
|
|
558 |
htmlspecialchars($varname) . ", but got $endedby");
|
|
|
559 |
}
|
|
|
560 |
|
|
|
561 |
// Get value
|
|
|
562 |
list($val, $endedby) = token_get_string($tokens);
|
|
|
563 |
|
|
|
564 |
if ($endedby != ',' && $endedby != ')') {
|
|
|
565 |
die("$path: Expected ending comma or bracket for key " .
|
|
|
566 |
htmlspecialchars($key) . " in array " .
|
|
|
567 |
htmlspecialchars($varname) . ", but got $endedby");
|
|
|
568 |
}
|
|
|
569 |
|
|
|
570 |
// Put the data in the environment.
|
|
|
571 |
$fullvar = $varname . '[' . $key . ']';
|
|
|
572 |
eval("$fullvar = '" . urlencode($val) . "';");
|
|
|
573 |
|
|
|
574 |
// Keep track of data flagged deprecated.
|
|
|
575 |
if ($in_deprecated) {
|
|
|
576 |
eval("\$DEPRECATED[$key] = true;");
|
|
|
577 |
}
|
|
|
578 |
|
|
|
579 |
// Last key/value pair?
|
|
|
580 |
if ($endedby == ')') break;
|
|
|
581 |
token_skip_whitespace($tokens);
|
|
|
582 |
if ($tokens[0] == ')') {
|
|
|
583 |
array_shift($tokens);
|
|
|
584 |
break;
|
|
|
585 |
}
|
|
|
586 |
}
|
|
|
587 |
} else {
|
|
|
588 |
list($varvalue,$endedby) = token_get_string($tokens);
|
|
|
589 |
eval("$varname = '" . urlencode($varvalue) . "';");
|
|
|
590 |
}
|
|
|
591 |
}
|
|
|
592 |
}
|
|
|
593 |
}
|
|
|
594 |
|
|
|
595 |
if ($keep_comment == '') {
|
|
|
596 |
$keep_comment = <<<HELP
|
|
|
597 |
## For adding information to the start of this language file,
|
|
|
598 |
## you can use comments starting with "##". Those comments will
|
|
|
599 |
## be kept intact when a new language file is generated by the
|
|
|
600 |
## language file maintenance software.
|
|
|
601 |
HELP;
|
|
|
602 |
}
|
|
|
603 |
|
|
|
604 |
// These aren't inside $PHORUM, but we put them there so we have
|
|
|
605 |
// access to them later on.
|
|
|
606 |
$PHORUM['STORE']['language_hide'] = $language_hide;
|
|
|
607 |
$PHORUM['STORE']['language'] = $language;
|
|
|
608 |
$PHORUM['STORE']['keep_comment'] = $keep_comment;
|
|
|
609 |
$PHORUM['STORE']['DEPRECATED'] = $DEPRECATED;
|
|
|
610 |
|
|
|
611 |
if (TOKEN_DEBUGGER){
|
|
|
612 |
print_var($PHORUM);
|
|
|
613 |
}
|
|
|
614 |
return $PHORUM;
|
|
|
615 |
}
|
|
|
616 |
|
|
|
617 |
|
|
|
618 |
// ======================================================================
|
|
|
619 |
// Extracting language strings from distribution files
|
|
|
620 |
// ======================================================================
|
|
|
621 |
|
|
|
622 |
function phorum_extract_language_strings()
|
|
|
623 |
{
|
|
|
624 |
global $extract_strings;
|
|
|
625 |
$extract_strings = array();
|
|
|
626 |
phorum_extract_language_strings_recurse(".");
|
|
|
627 |
return $extract_strings;
|
|
|
628 |
}
|
|
|
629 |
|
|
|
630 |
// This function processes directories recursively to search
|
|
|
631 |
// for language strings.
|
|
|
632 |
function phorum_extract_language_strings_recurse($path)
|
|
|
633 |
{
|
|
|
634 |
global $extract_strings;
|
|
|
635 |
|
|
|
636 |
$dh = opendir($path);
|
|
|
637 |
while (($f = readdir($dh)))
|
|
|
638 |
{
|
|
|
639 |
$file = "$path/$f";
|
|
|
640 |
|
|
|
641 |
$ext = null;
|
|
|
642 |
if (preg_match('/\.(\w+)$/', $f, $m)) $ext = $m[1];
|
|
|
643 |
|
|
|
644 |
// Skip what we do not want to index.
|
|
|
645 |
if ($f == "." || $f == "..") continue; // this and parent dir
|
|
|
646 |
if ($f == ".svn") continue; // SVN data directories
|
|
|
647 |
if ($f == "lang") continue; // language files
|
|
|
648 |
if ($f == "mods") continue; // mods
|
|
|
649 |
if ($f == "docs") continue; // documentation
|
|
|
650 |
if ($f == "cache") continue; // the cache directory
|
|
|
651 |
|
|
|
652 |
|
|
|
653 |
if (preg_match('/\.(php|tpl)$/', $file)) {
|
|
|
654 |
$fp = fopen($file, "r");
|
|
|
655 |
if (! $fp) die("Can't read file '$file'");
|
|
|
656 |
while (($line = fgets($fp, 1024))) {
|
|
|
657 |
$strings = array();
|
|
|
658 |
if (preg_match_all('/LANG->([\w_-]+)/', $line, $m, PREG_SET_ORDER)) {
|
|
|
659 |
$strings = array_merge($strings, $m);
|
|
|
660 |
}
|
|
|
661 |
if (preg_match_all('/\$PHORUM\[["\']DATA["\']\]\[["\']LANG["\']\]\[["\']([^"\']+)["\']\]/', $line, $m, PREG_SET_ORDER)) {
|
|
|
662 |
$strings = array_merge($strings, $m);
|
|
|
663 |
}
|
|
|
664 |
foreach ($strings as $string) {
|
|
|
665 |
if (! isset($extract_strings[$string])) {
|
|
|
666 |
$extract_strings[$string] = array('files'=>array());
|
|
|
667 |
}
|
|
|
668 |
$extract_strings[$string[1]]['files'][$file]++;
|
|
|
669 |
$extract_strings[$string[1]]['source'][$string[0]]++;
|
|
|
670 |
|
|
|
671 |
}
|
|
|
672 |
}
|
|
|
673 |
fclose($fp);
|
|
|
674 |
}
|
|
|
675 |
|
|
|
676 |
if (is_dir($file)) {
|
|
|
677 |
phorum_extract_language_strings_recurse($file);
|
|
|
678 |
}
|
|
|
679 |
}
|
|
|
680 |
closedir($dh);
|
|
|
681 |
}
|
|
|
682 |
?>
|