Elgg  Version master
ReleaseCleaner.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\I18n;
4 
6 use Elgg\Includer;
8 
15 
19  private $codes;
20 
24  public $log = [];
25 
31  public function __construct(array $codes = []) {
32  if (empty($codes)) {
33  $codes = _elgg_services()->locale->getLanguageCodes();
34  }
35 
36  $this->codes = $codes;
37  }
38 
46  public function cleanInstallation(string $dir): void {
47  $dir = Paths::sanitize($dir, false);
48 
49  if (is_dir("{$dir}/install/languages")) {
50  $this->cleanLanguagesDir("{$dir}/install/languages");
51  }
52 
53  if (is_dir("{$dir}/languages")) {
54  $this->cleanLanguagesDir("{$dir}/languages");
55  }
56 
57  $mods = new \DirectoryIterator("{$dir}/mod");
58 
59  foreach ($mods as $mod) {
60  if ($mod->isDot() || !$mod->isDir()) {
61  continue;
62  }
63 
64  if (!in_array($mod->getFilename(), Plugins::BUNDLED_PLUGINS)) {
65  // not a core plugin
66  continue;
67  }
68 
69  if (is_dir("{$mod->getPathname()}/languages")) {
70  // only process plugins which have translations
71  $this->cleanLanguagesDir("{$mod->getPathname()}/languages");
72  }
73  }
74  }
75 
83  public function cleanLanguagesDir(string $dir): void {
84  $dir = Paths::sanitize($dir, false);
85 
86  $files = new \DirectoryIterator($dir);
87  foreach ($files as $file) {
88  if ($file->isDot() || !$file->isFile()) {
89  continue;
90  }
91 
92  if ($file->getExtension() !== 'php') {
93  continue;
94  }
95 
96  $code = $file->getBasename('.php');
97  if (!in_array($code, $this->codes)) {
99 
100  if (in_array($code, $this->codes)) {
101  // rename file to lowercase
102  rename($file->getPathname(), "{$dir}/{$code}.php");
103  $this->log[] = "Renamed {$file->getPathname()} to {$code}.php";
104  } else {
105  unlink($file->getPathname());
106  $this->log[] = "Removed {$file->getPathname()}";
107  }
108  }
109 
110  if ($code !== 'en' && file_exists("{$dir}/{$code}.php")) {
111 // $this->detectAdditionalKeys($dir, $code);
112 // $this->detectIdenticalTranslations($dir, $code);
114  $this->cleanupEmptyTranslations("{$dir}/{$code}.php");
115  }
116  }
117  }
118 
127  protected function cleanupMissingTranslationParameters(string $directory, string $language_code): void {
128  $english = Includer::includeFile("{$directory}/en.php");
129  $translation = Includer::includeFile("{$directory}/{$language_code}.php");
130 
131  foreach ($english as $key => $value) {
132  $english_matches = preg_match_all('/%[a-zA-Z]/m', $value);
133  if (!array_key_exists($key, $translation) || $english_matches === false) {
134  continue;
135  }
136 
137  $translation_matches = preg_match_all('/%[a-zA-Z]/m', $translation[$key]);
138  if ($translation_matches !== false && $english_matches === $translation_matches) {
139  continue;
140  }
141 
142  $file_contents = file_get_contents("{$directory}/{$language_code}.php");
143 
144  $pattern = '/^\s*[\'"]' . $key . '[\'"] => [\'"]' . preg_quote($translation[$key], '/') . '[\'"],{0,1}\R/m';
145  $count = 0;
146  $file_contents = preg_replace($pattern, '', $file_contents, -1, $count);
147  if ($count < 1) {
148  // try to add slashes for quotes
149  $pattern = '/^\s*[\'"]' . $key . '[\'"] => [\'"]' . preg_quote(addslashes($translation[$key]), '/') . '[\'"],{0,1}\R/m';
150  $count = 0;
151  $file_contents = preg_replace($pattern, '', $file_contents, -1, $count);
152  }
153 
154  if ($count > 0) {
155  file_put_contents("{$directory}/{$language_code}.php", $file_contents);
156  } else {
157  $this->log[] = "Unable to repair mismatch in translation argument count in {$directory}/{$language_code}.php for the key '{$key}'";
158  }
159  }
160  }
161 
169  protected function cleanupEmptyTranslations(string $translation_file): void {
170  $contents = file_get_contents($translation_file);
171  if (empty($contents)) {
172  return;
173  }
174 
175  $pattern = '/^\s*[\'"].*[\'"] => [\'"]{2},{0,1}\R/m';
176  $count = 0;
177  $contents = preg_replace($pattern, '', $contents, -1, $count);
178 
179  if ($count > 0) {
180  // something was changed
181  file_put_contents($translation_file, $contents);
182 
183  $this->log[] = "Cleaned empty translations from {$translation_file}";
184  }
185  }
186 
194  protected function normalizeLanguageCode(string $code): string {
195  $code = strtolower($code);
196  return preg_replace('~[^a-z0-9]~', '_', $code);
197  }
198 
207  protected function detectAdditionalKeys(string $directory, string $language_code): void {
208  $english = Includer::includeFile("{$directory}/en.php");
209  $translation = Includer::includeFile("{$directory}/{$language_code}.php");
210 
211  foreach ($translation as $key => $value) {
212  if (array_key_exists($key, $english)) {
213  continue;
214  }
215 
216  $this->log[] = "The translation key '{$key}' exists in the '{$language_code}' translation but not in English";
217  }
218  }
219 
228  protected function detectIdenticalTranslations(string $directory, string $language_code): void {
229  $english = Includer::includeFile("{$directory}/en.php");
230  $translation = Includer::includeFile("{$directory}/{$language_code}.php");
231 
232  foreach ($translation as $key => $value) {
233  if (!array_key_exists($key, $english)) {
234  // shouldn't happen
235  continue;
236  }
237 
238  if (strlen($key) < 3) {
239  // probably a language code
240  continue;
241  }
242 
243  if ($english[$key] !== $value) {
244  continue;
245  }
246 
247  $this->log[] = "The translation key '{$key}' in the '{$language_code}' translation is identical to the English translation";
248  }
249  }
250 }
static includeFile($file)
Include a file with as little context as possible.
Definition: Includer.php:18
Removes invalid language files from an installation.
detectAdditionalKeys(string $directory, string $language_code)
Detect translation keys that (still) exist in a translation but no longer in the English translation...
c Accompany it with the information you received as to the offer to distribute corresponding source complete source code means all the source code for all modules it plus any associated interface definition plus the scripts used to control compilation and installation of the executable as a special the source code distributed need not include anything that is normally and so on of the operating system on which the executable unless that component itself accompanies the executable If distribution of executable or object code is made by offering access to copy from a designated then offering equivalent access to copy the source code from the same place counts as distribution of the source even though third parties are not compelled to copy the source along with the object code You may not or distribute the Program except as expressly provided under this License Any attempt otherwise to sublicense or distribute the Program is void
Definition: LICENSE.txt:215
cleanupMissingTranslationParameters(string $directory, string $language_code)
Try to cleanup translations with a different argument count than English as this can cause failed tra...
cleanupEmptyTranslations(string $translation_file)
Remove empty translations from a translation file.
cleanLanguagesDir(string $dir)
Clean up a languages dir.
$value
Definition: generic.php:51
normalizeLanguageCode(string $code)
Normalize a language code (e.g.
__construct(array $codes=[])
Constructor.
$count
Definition: ban.php:24
if($container instanceof ElggGroup &&$container->guid!=elgg_get_page_owner_guid()) $key
Definition: summary.php:44
log($level, $message, array $context=[])
Log a message.
Definition: Loggable.php:58
cleanInstallation(string $dir)
Clean up within an installation.
detectIdenticalTranslations(string $directory, string $language_code)
Detect identical translations, this could be due to a wrong Transifex import.
static sanitize($path, $append_slash=true)
Sanitize file paths ensuring that they begin and end with slashes etc.
Definition: Paths.php:76
_elgg_services()
Get the global service provider.
Definition: elgglib.php:346
if(!$plugin instanceof\ElggPlugin) $file_contents
if(!empty($title)&&!empty($icon_name)) if(!empty($title)) if(!empty($menu)) if(!empty($header)) if(!empty($body)) $contents
Definition: message.php:73