Subversion Repositories Applications.papyrus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
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
?>