]> BookStack Code Mirror - bookstack/blob - resources/lang/format.php
8698d1bb7d1639e69362432b335a3f295ff97a4e
[bookstack] / resources / lang / format.php
1 #!/usr/bin/env php
2 <?php
3
4 /**
5  * Format a language file in the same way as the EN equivalent.
6  * Matches the line numbers of translated content.
7  */
8
9 $args = array_slice($argv, 1);
10
11 if (count($args) < 2) {
12     errorOut("Please provide a language code as the first argument and a translation file name as the second (./format.php fr activities)");
13 }
14
15 $lang = formatLang($args[0]);
16 $fileName = explode('.', $args[1])[0];
17
18 $enLines = loadLangFileLines('en', $fileName);
19 $langContent = loadLang($lang, $fileName);
20 $enContent = loadLang('en', $fileName);
21
22 // Calculate the longest top-level key length
23 $longestKeyLength = longestKey($enContent);
24
25 // Start formatted content
26 $formatted = [];
27 $mode = 'header';
28 $arrayKeys = [];
29
30 foreach($enLines as $index => $line) {
31     $trimLine = trim($line);
32     if ($mode === 'header') {
33         $formatted[$index] = $line;
34         if (str_replace(' ', '', $trimLine) === 'return[') $mode = 'body';
35     }
36
37     if ($mode === 'body') {
38         $matches = [];
39
40         // Comment
41         if (strpos($trimLine, '//') === 0) {
42             $formatted[$index] = "\t" . $trimLine;
43             continue;
44         }
45
46         // Arrays
47         $arrayStartMatch = preg_match('/^\'(.*)\'\s+?=>\s+?\[(\],)?\s*?$/', $trimLine, $matches);
48         $arrayEndMatch = preg_match('/]\s*,\s*$/', $trimLine);
49         $indent = count($arrayKeys) + 1;
50         if ($arrayStartMatch === 1) {
51             $arrayKeys[] = $matches[1];
52             $formatted[$index] = str_repeat(" ", $indent * 4) . str_pad("'{$matches[1]}'", $longestKeyLength) . "=> [";
53             if ($arrayEndMatch !== 1) continue;
54         }
55         if ($arrayEndMatch === 1) {
56             unsetArrayByKeys($langContent, $arrayKeys);
57             $key = array_pop($arrayKeys);
58             if (isset($formatted[$index])) {
59                 $formatted[$index] .= '],';
60             } else {
61                 $formatted[$index] = str_repeat(" ", ($indent-1) * 4) . "],";
62             }
63             continue;
64         }
65
66         // Translation
67         $translationMatch = preg_match('/^\'(.*)\'\s+?=>\s+?\'(.*)?\'.+?$/', $trimLine, $matches);
68         if ($translationMatch === 1) {
69             $key = $matches[1];
70             $keys = array_merge($arrayKeys, [$key]);
71             $langVal = getTranslationByKeys($langContent, $keys);
72             if (empty($langVal)) continue;
73
74             $keyPad = $longestKeyLength;
75             if (count($arrayKeys) === 0) {
76                 unset($langContent[$key]);
77             } else {
78                 $keyPad = longestKey(getTranslationByKeys($enContent, $arrayKeys));
79             }
80
81             $formatted[$index] = formatTranslationLine($key, $langVal, $indent, $keyPad);
82             continue;
83         }
84     }
85
86 }
87
88 // Fill missing lines
89 $arraySize = max(array_keys($formatted));
90 $formatted = array_replace(array_fill(0, $arraySize, ''), $formatted);
91
92 // Add remaining translations
93 $langContent = array_filter($langContent, function($item) {
94     return !is_null($item) && !empty($item);
95 });
96 if (count($langContent) > 0) {
97     $formatted[] = '';
98     $formatted[] = "\t// Unmatched";
99 }
100 foreach ($langContent as $key => $value) {
101     if (is_array($value)) {
102         $formatted[] = formatTranslationArray($key, $value);
103     } else {
104         $formatted[] = formatTranslationLine($key, $value);
105     }
106 }
107
108 // Add end line
109 $formatted[] = '];';
110 $formatted = implode("\n", $formatted);
111
112 writeLangFile($lang, $fileName, $formatted);
113
114 function formatTranslationLine(string $key, string $value, int $indent = 1, int $keyPad = 1) {
115     $escapedValue = str_replace("'", "\\'", $value);
116     return str_repeat(" ", $indent * 4) . str_pad("'{$key}'", $keyPad, ' ') ."=> '{$escapedValue}',";
117 }
118
119 function longestKey(array $array) {
120     $top = 0;
121     foreach ($array as $key => $value) {
122         $keyLen = strlen($key);
123         $top = max($top, $keyLen);
124     }
125     return $top + 3;
126 }
127
128 function formatTranslationArray(string $key, array $array) {
129     $arrayPHP = var_export($array, true);
130     return "    '{$key}' => {$arrayPHP},";
131 }
132
133 function getTranslationByKeys(array $translations, array $keys) {
134     $val = $translations;
135     foreach ($keys as $key) {
136         $val = $val[$key] ?? '';
137         if ($val === '') return '';
138     }
139     return $val;
140 }
141
142 function unsetArrayByKeys(array &$input, array $keys) {
143     $val = &$input;
144     $lastIndex = count($keys) - 1;
145     foreach ($keys as $index => &$key) {
146         if ($index === $lastIndex && is_array($val)) {
147             unset($val[$key]);
148         }
149         if (!is_array($val)) return;
150         $val = &$val[$key] ?? [];
151     }
152 }
153
154 function writeLangFile(string $lang, string $fileName, string $content) {
155     $path = __DIR__ . "/{$lang}/{$fileName}.php";
156     if (!file_exists($path)) {
157         errorOut("Expected translation file '{$path}' does not exist");
158     }
159     file_put_contents($path, $content);
160 }
161
162 function loadLangFileLines(string $lang, string $fileName) {
163     $path = __DIR__ . "/{$lang}/{$fileName}.php";
164     if (!file_exists($path)) {
165         errorOut("Expected translation file '{$path}' does not exist");
166     }
167     $lines = explode("\n", file_get_contents($path));
168     return array_map(function($line) {
169         return trim($line, "\r");
170     }, $lines);
171 }
172
173 function loadLang(string $lang, string $fileName) {
174     $path = __DIR__ . "/{$lang}/{$fileName}.php";
175     if (!file_exists($path)) {
176         errorOut("Expected translation file '{$path}' does not exist");
177     }
178
179     $fileData = include($path);
180     return $fileData;
181 }
182
183 function formatLang($lang) {
184     $langParts = explode('_', strtoupper($lang));
185     $langParts[0] = strtolower($langParts[0]);
186     return implode('_', $langParts);
187 }
188
189 function dd($content) {
190     print_r($content);
191     exit(1);
192 }
193
194 function info($text) {
195     echo "\e[34m" . $text . "\e[0m\n";
196 }
197
198 function errorOut($text) {
199     echo "\e[31m" . $text . "\e[0m\n";
200     exit(1);
201 }