*/ private static function usedKeys(): array { $root = dirname(__DIR__); $keys = []; $files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($root . '/src')); foreach ($files as $file) { if ($file->getExtension() !== 'php') { continue; } $code = (string)file_get_contents($file->getPathname()); preg_match_all("/Lang::t\\('((?:[^'\\\\]|\\\\.)+)'/", $code, $calls); preg_match_all("/string \\\$title = '([^']+)'/", $code, $titles); array_push($keys, ...$calls[1], ...$titles[1]); } array_push($keys, ...(new GameData($root . '/assets/data'))->textKeys()); return array_values(array_unique($keys)); } private static function tables(): array { return Yaml::parseFile(dirname(__DIR__) . '/config/lang.yaml'); } public function testEveryLanguageOfThePlaygroundHasATable(): void { self::assertSame(self::LANGUAGES, array_keys(self::tables())); self::assertSame(['en', ...self::LANGUAGES], array_keys(FontProvider::LANGUAGES)); } public function testEveryKeyUsedIsTranslatedInEveryLanguage(): void { $tables = self::tables(); $missing = []; foreach (self::usedKeys() as $key) { foreach (self::LANGUAGES as $lang) { $text = $tables[$lang][$key] ?? null; if (!is_string($text) || $text === '') { $missing[] = "$lang: $key"; } } } self::assertSame([], $missing); } public function testEveryTranslationIsUsed(): void { $used = array_flip(self::usedKeys()); $unused = []; foreach (self::tables() as $lang => $table) { foreach (array_keys($table) as $key) { if (!isset($used[$key])) { $unused[] = "$lang: $key"; } } } self::assertSame([], $unused); } public function testTranslationsKeepTheirPlaceholders(): void { $wrong = []; foreach (self::tables() as $lang => $table) { foreach ($table as $key => $text) { // the same placeholders, in any order (word order changes between languages) preg_match_all('/\{\w+\}/', (string)$key, $a); preg_match_all('/\{\w+\}/', (string)$text, $b); sort($a[0]); sort($b[0]); if ($a[0] !== $b[0]) { $wrong[] = "$lang: $key"; } } } self::assertSame([], $wrong); } }