1 |
<?php |
2 |
|
3 |
/* |
4 |
* This is a file parser to extract localizable strings from moonmoon |
5 |
* |
6 |
* It will scan the whole moonmoon repository for php files, extract |
7 |
* localized strings and their localization notes and create .lang files. |
8 |
* Existing translations will be automatically updated. |
9 |
* A short report will be displayed afterwards. |
10 |
* |
11 |
* The easiest way to add a new locale is just to create an empty .lang file and then run the script |
12 |
* |
13 |
* The script scans for the files in the l10n/ folder to know which locales are supported |
14 |
*/ |
15 |
|
16 |
// released versions of moonmoon should immediately return for security |
17 |
// return; |
18 |
|
19 |
$root = dirname(__FILE__) . '/../../'; |
20 |
$GLOBALS['english'] = array(); |
21 |
|
22 |
include_once $root . '/app/classes/Simplel10n.class.php'; |
23 |
|
24 |
/* |
25 |
* This is a file parser to extract localizable strings (in .php files) |
26 |
* $GLOBALS['english'] is populated with localizable strings and their associated localization notes |
27 |
* |
28 |
*/ |
29 |
|
30 |
|
31 |
function extract_l10n_strings($file) { |
32 |
$lines = file($file); |
33 |
$patterns = array('/_g\([\'"](.*?)[\'"]\)/', '/getString\([\'"](.*?)[\'"]\)/',); |
34 |
|
35 |
foreach ($lines as $line) { |
36 |
|
37 |
// Skip comments |
38 |
if($line[0] == '#' || $line[0] == '/') continue; |
39 |
|
40 |
// parsing logic |
41 |
foreach($patterns as $pattern) { |
42 |
if(preg_match_all($pattern, $line, $matches, PREG_PATTERN_ORDER)) { |
43 |
foreach($matches[1] as $val) { |
44 |
|
45 |
// Do not extract php variables calls or empty strings |
46 |
if($val[0] == '$' || $val == '') continue; |
47 |
|
48 |
// Is there a localization comment ? |
49 |
$l10n_note = explode("',", $val); |
50 |
|
51 |
// Also test strings in double quotes |
52 |
if(count($l10n_note) == 1) { |
53 |
$l10n_note = explode('",', $val); |
54 |
} |
55 |
|
56 |
// Extract cleaned up strings |
57 |
if(count($l10n_note) == 2) { |
58 |
$l10n_str = trim($l10n_note[0]); |
59 |
$l10n_note = trim(substr(trim($l10n_note[1]),1)); # Remove quote at begining of string |
60 |
} else { |
61 |
$l10n_str = trim($val); |
62 |
$l10n_note = ''; |
63 |
} |
64 |
|
65 |
if(!array_key_exists($l10n_str, $GLOBALS['english'])) { |
66 |
$GLOBALS['english'][$l10n_str] = array($l10n_str, $l10n_note); |
67 |
} |
68 |
} |
69 |
} |
70 |
} |
71 |
} |
72 |
} |
73 |
|
74 |
/* |
75 |
* This is a function echoing $GLOBALS['english'] in .lang format |
76 |
* Typical usage would be: |
77 |
* <?php |
78 |
* extract_l10n_strings('.'); |
79 |
* show_l10n_strings() ; |
80 |
*/ |
81 |
|
82 |
function show_l10n_strings() { |
83 |
|
84 |
header('Content-Type:text/plain'); |
85 |
|
86 |
foreach($GLOBALS['english'] as $val) { |
87 |
if($val[1]) { |
88 |
echo '# ' . $val[1] . "\n"; |
89 |
} |
90 |
echo ";$val[0]\n"; |
91 |
echo "$val[0]\n\n\n"; |
92 |
} |
93 |
} |
94 |
|
95 |
/* |
96 |
* Recursively scan files in a folder |
97 |
* returns an array of file paths |
98 |
*/ |
99 |
|
100 |
function find_all_files($dir) { |
101 |
|
102 |
$result = array(); |
103 |
$root = scandir($dir); |
104 |
|
105 |
$ignore = array('.', '..', '.git', '.svn', '.hg', 'cache', '.gitignore', 'lib'); |
106 |
|
107 |
foreach($root as $value) { |
108 |
|
109 |
if(in_array($value, $ignore)) { |
110 |
continue; |
111 |
} |
112 |
|
113 |
if(is_file("$dir/$value")) { |
114 |
$split = explode('.', $value); |
115 |
if(end($split) == 'php'){ |
116 |
$result[] = "$dir/$value"; |
117 |
} |
118 |
continue; |
119 |
} |
120 |
|
121 |
foreach(find_all_files("$dir/$value") as $value) { |
122 |
$result[]=$value; |
123 |
} |
124 |
} |
125 |
|
126 |
return $result; |
127 |
} |
128 |
|
129 |
function update_lang_files($source, $dest) { |
130 |
|
131 |
$files = find_all_files($source); |
132 |
|
133 |
foreach($files as $file) { |
134 |
extract_l10n_strings($file); |
135 |
} |
136 |
|
137 |
|
138 |
$files = scandir($dest); |
139 |
$ignore = array('.', '..'); |
140 |
|
141 |
|
142 |
// list locales |
143 |
$locales = array(); |
144 |
foreach($files as $file) { |
145 |
|
146 |
if(in_array($file, $ignore)) { |
147 |
continue; |
148 |
} |
149 |
|
150 |
$split = explode('.', $file); |
151 |
|
152 |
if($split[1] == 'lang') { |
153 |
$locales[] = $split[0]; |
154 |
} |
155 |
} |
156 |
|
157 |
|
158 |
foreach($locales as $locale) { |
159 |
$status[$locale] = 0; |
160 |
$lang_file_path = $dest . '/' . $locale; |
161 |
|
162 |
Simplel10n::load($lang_file_path); |
163 |
|
164 |
ob_start(); |
165 |
foreach($GLOBALS['english'] as $key => $val) { |
166 |
$warning = ''; |
167 |
$value = @Simplel10n::extractString($key); |
168 |
|
169 |
if($value == $val[0]) { |
170 |
$status[$locale]++; |
171 |
$warning = ' ** String needs translation **'; |
172 |
} |
173 |
|
174 |
if($val[1]) { |
175 |
echo '# Translation note: ' . $val[1] . $warning . "\n"; |
176 |
} elseif($warning != '') { |
177 |
echo '# Translation note: ' . $warning . "\n"; |
178 |
} |
179 |
|
180 |
echo ";$val[0]\n"; |
181 |
echo $value . "\n\n\n"; |
182 |
} |
183 |
|
184 |
$content = ob_get_contents(); |
185 |
ob_end_clean(); |
186 |
file_put_contents($lang_file_path. '.lang', $content); |
187 |
|
188 |
unset($GLOBALS['locale']); |
189 |
} |
190 |
|
191 |
|
192 |
// Display a short status report |
193 |
header('Content-Type:text/plain'); |
194 |
echo "Number of English strings: " . count($GLOBALS['english']) . "\n"; |
195 |
echo "Your installation has these languages installed: " . implode(', ', $locales) . "\n"; |
196 |
foreach($locales as $val) { |
197 |
echo $val . " has " . $status[$val] . " untranslated strings.\n"; |
198 |
} |
199 |
} |
200 |
|
201 |
update_lang_files($root, $root . 'app/l10n'); |