[ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Language file tests inspired by the script by schplurtz 5 * @link https://www.dokuwiki.org/teams:i18n:translation-check 6 */ 7 class lang_test extends DokuWikiTest 8 { 9 /** 10 * returen all languages except english 11 * 12 * @return string[] 13 */ 14 protected function findLanguages() 15 { 16 $languages = glob(DOKU_INC . 'inc/lang/*', GLOB_ONLYDIR); 17 $languages = array_map('basename', $languages); 18 $languages = array_filter($languages, function ($in) { 19 return $in !== 'en'; 20 }); 21 return $languages; 22 } 23 24 /** 25 * Get all installed plugins 26 * 27 * This finds all things that might be a plugin and does not care for enabled or not. 28 * 29 * @return string[] 30 */ 31 protected function findPlugins() 32 { 33 $plugins = glob(DOKU_INC . 'lib/plugins/*', GLOB_ONLYDIR); 34 return $plugins; 35 } 36 37 /** 38 * Get all installed templates 39 * 40 * This finds all things that might be a template and does not care for enabled or not. 41 * 42 * @return string[] 43 */ 44 protected function findTemplates() 45 { 46 $templates = glob(DOKU_INC . 'lib/tpl/*', GLOB_ONLYDIR); 47 return $templates; 48 } 49 50 /** 51 * Load the strings for the given language 52 * 53 * @param string $lang 54 * @return array 55 */ 56 protected function loadLanguage($file) 57 { 58 $lang = []; 59 if (file_exists($file)) { 60 include $file; 61 } 62 return $lang; 63 } 64 65 /** 66 * Provide all the language files to compare 67 * 68 * @return Generator 69 */ 70 public function provideLanguageFiles() 71 { 72 $bases = array_merge( 73 [DOKU_INC . 'inc'], 74 $this->findPlugins(), 75 $this->findTemplates() 76 ); 77 78 foreach ($this->findLanguages() as $code) { 79 foreach ($bases as $base) { 80 foreach (['lang.php', 'settings.php'] as $file) { 81 $englishFile = "$base/lang/en/$file"; 82 $foreignFile = "$base/lang/$code/$file"; 83 $name = substr($foreignFile, strlen(DOKU_INC)); 84 $name = '…'.substr($name, -35); 85 86 if (file_exists($foreignFile)) { 87 yield ([ 88 $this->loadLanguage($englishFile), 89 $this->loadLanguage($foreignFile), 90 $code, 91 $name, 92 ]); 93 } 94 } 95 } 96 } 97 } 98 99 /** 100 * Check for obsolete language strings 101 * 102 * @param array $english key/value language pairs for English 103 * @param array $foreign key/value language pairs for the foreign language 104 * @param string $code language code of the foreign file 105 * @param string $file the base file name the foreign keys came from 106 * @param string $prefix sub key that is currently checked (used in recursion) 107 * @dataProvider provideLanguageFiles 108 */ 109 public function testObsolete($english, $foreign, $code, $file, $prefix = '') 110 { 111 $this->assertGreaterThan(0, count($foreign), "$file exists but has no translations"); 112 113 foreach ($foreign as $key => $value) { 114 $name = $prefix ? $prefix . $key : $key; 115 $this->assertArrayHasKey($key, $english, "$file: obsolete/unknown key '$name'"); 116 117 // sub arrays as for the js translations: 118 if (is_array($value) && is_array($english[$key])) { 119 $this->testObsolete($english[$key], $value, $code, $file, $key); 120 } 121 } 122 } 123 124 /** 125 * Check for sprintf format placeholder equality 126 * 127 * @param array $english key/value language pairs for English 128 * @param array $foreign key/value language pairs for the foreign language 129 * @param string $code language code of the foreign file 130 * @param string $file the base file name the foreign keys came from 131 * @param string $prefix sub key that is currently checked (used in recursion) 132 * @dataProvider provideLanguageFiles 133 */ 134 public function testPlaceholders($english, $foreign, $code, $file, $prefix = '') 135 { 136 $this->assertGreaterThan(0, count($foreign), "$file exists but has no translations"); 137 138 foreach ($foreign as $key => $value) { 139 // non existing in english is skipped here, that what testObsolete checks 140 if (!isset($english[$key])) continue; 141 142 // sub arrays as for the js translations: 143 if (is_array($value) && is_array($english[$key])) { 144 $this->testPlaceholders($english[$key], $value, $code, $file, $key); 145 return; 146 } 147 148 $name = $prefix ? $prefix . $key : $key; 149 150 $englishPlaceholders = $this->parsePlaceholders($english[$key]); 151 $foreignPlaceholders = $this->parsePlaceholders($value); 152 $countEnglish = count($englishPlaceholders); 153 $countForeign = count($foreignPlaceholders); 154 155 $this->assertEquals($countEnglish, $countForeign, 156 join("\n", 157 [ 158 "$file: unequal amount of sprintf format placeholders in '$name'", 159 "en: '" . $english[$key] . "'", 160 "$code: '$value'", 161 ] 162 ) 163 ); 164 165 $this->assertEquals($englishPlaceholders, $foreignPlaceholders, 166 join("\n", 167 [ 168 "$file: sprintf format mismatch in '$name'", 169 "en: '" . $english[$key] . "'", 170 "$code: '$value'", 171 ] 172 ) 173 ); 174 } 175 } 176 177 /** 178 * Parses the placeholders from a string and brings them in the correct order 179 * 180 * This has its own test below. 181 * 182 * @param string $string 183 */ 184 protected function parsePlaceholders($string) 185 { 186 if (!preg_match_all('/%(?:([0-9]+)\$)?([-.0-9hl]*?[%dufsc])/', $string, $matches, PREG_SET_ORDER)) { 187 return []; 188 } 189 190 // Given this string : 'schproutch %2$s with %1$04d in %-20s plouf' 191 // we have this in $matches: 192 // [ 193 // 0 => ['%2$s', 2, 's'], 194 // 1 => ['%1$04d', 1, '04d'], 195 // 2 => ['%-20s', '', '-20s'], 196 // ] 197 198 // sort by the given sorting in key 1 199 usort($matches, function ($a, $b) { 200 if ($a[1] === $b[1]) return 0; // keep as is 201 202 // sort empties towards the back 203 if ($a[1] === '') $a[1] = 9999; 204 if ($b[1] === '') $b[1] = 9999; 205 206 // compare sort numbers 207 if ((int)$a[1] < (int)$b[1]) return -1; 208 if ((int)$a[1] > (int)$b[1]) return 1; 209 return 0; 210 }); 211 212 // return values in key 2 213 return array_column($matches, 2); 214 } 215 216 /** 217 * Dataprovider for the parsePlaceholder test 218 * @return array[] 219 */ 220 public function providePlaceholders() 221 { 222 return [ 223 ['schproutch %2$s with %1$04d in %-20s plouf', ['04d', 's', '-20s']], 224 ]; 225 } 226 227 /** 228 * Test the parsePlaceholder utility function above 229 * 230 * @param string $input 231 * @param array $expected 232 * @dataProvider providePlaceholders 233 */ 234 public function testParsePlaceholders($input, $expected) 235 { 236 $this->assertEquals($expected, $this->parsePlaceholders($input)); 237 } 238 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body