File: D:/HostingSpaces/SBogers10/gggg.komma.nl/vendor/komma/kms/tests/Unit/TranslationFilesTest.php
<?php
namespace Tests\Unit;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Str;
use Illuminate\Translation\FileLoader;
use Komma\KMS\Core\Translator;
use Tests\TestCase;
/**
* Class TranslationFiles
*
* Tests translation files for the other languages contains the same keys
*
* @package Tests\Unit
*/
class TranslationFilesTest extends TestCase
{
private Translator $trans;
private Filesystem $fileSystem;
private array $translationKeys = [];
private array $languageFunctionPatterns = [
"/__\('(.*?)'[),]/",
"/trans\('(.*?)'[),]/",
"/lang\('(.*?)'[),]/"
];
private array $skippableStartKeys = [
'routes',
'KMS::prevent_navigation', // Skipped because of array usage
'KMS::validation.min',
'KMS::attributes/components.types',
'KMS::calendar',
'KMS::global',
'KMS::outofdate',
'attributes/components.types', // Skipped because of generic usage
'passwords.',
'roles.',
'transfer.',
'validation.',
'sidebarMenu.',
'auth.validation.throttled',
];
private array $skippableEndKeys = [
'.section.new',
'.section.title',
];
public function __construct($name = null, array $data = [], $dataName = '')
{
parent::__construct($name, $data, $dataName);
$this->fileSystem = new Filesystem();
$loader = new FileLoader($this->fileSystem, realpath('./resources/lang'));
$this->trans = new Translator($loader, 'nl');
}
/**
* Setup the test environment.
*
* @throws \Exception
*/
protected function setUp(): void
{
parent::setUp();
$localLanguageFolder = realpath('./resources/lang/nl');
$this->assertFileExists($localLanguageFolder);
$fileSystem = new Filesystem();
$languageFiles = $fileSystem->allFiles($localLanguageFolder);
foreach ($languageFiles as $languageFile) {
$fileName = $languageFile->getRelativePathname();
$translationFileKey = Str::replaceLast('.' . $languageFile->getExtension(), '', $fileName);
$this->getKeysFromArray($translationFileKey);
}
}
/**
* Recurring function for grabbing the translations out of an array till it's a string
*
* @param string $translationParentKey
* @throws \Exception
*/
private function getKeysFromArray(string $translationParentKey)
{
foreach ($this->trans->get($translationParentKey, [], 'nl') as $translationKey => $translationValue) {
if(is_array($translationValue)) {
$this->getKeysFromArray($translationParentKey . '.' . $translationKey);
continue;
}
$this->assertIsString($translationValue);
$this->translationKeys[] = $translationParentKey . '.' . $translationKey;
}
}
/**
* @group TranslationFilesTest
* @test
* @throws \Exception
*/
public function checkUsageOfTranslations()
{
$fileList = [];
$this->addFilesContainLanguageFunctionsOutOfDirectory($fileList, realpath('./src'));
$this->addFilesContainLanguageFunctionsOutOfDirectory($fileList, realpath('./resources'));
// Create a list of all the used translation keys
$usedTranslationKeys = $this->createUsedTranslationKeysList($fileList);
// Copy the translations keys so we track if they are used
$unusedTranslationsKeys = $this->translationKeys;
$resolvedTranslationKeys = [];
// Loop through the used translations and validate that they are defined.
foreach ($usedTranslationKeys as $usedTranslationKey ) {
// echo $key . ': ' . $usedTranslationKey.PHP_EOL;
// Skip translations keys starting with, contains variables or already resolved keys
if(in_array($usedTranslationKey, $this->skippableStartKeys) || Str::contains($usedTranslationKey, ['.$', '. $', '($']) || in_array($usedTranslationKey, $resolvedTranslationKeys)) continue;
// Store original found translation key for the resolvedTranslationKeys
// Note: We kept append in the bottom to maintain the same flow as in the boiler plates
$originalTranslationKey = $usedTranslationKey;
// Remove the KMS:: prefix from the key
if(Str::startsWith($usedTranslationKey, 'KMS::')) $usedTranslationKey = Str::replaceFirst('KMS::', '', $usedTranslationKey);
// Validate that the translation is found
$this->assertContains($usedTranslationKey, $this->translationKeys, 'Found translation "' . $usedTranslationKey .'" is not defined in the languages files. Or possible with "KMS::"');
// Remove this translation key from the unusedTranslationsKeys because it is used
unset($unusedTranslationsKeys[array_search($usedTranslationKey, $unusedTranslationsKeys)]);
// Append the resolve translation, in case it is used multiple times
$resolvedTranslationKeys[] = $originalTranslationKey;
}
$unusedTranslationErrors = collect();
// Loop through the remaining defined translations keys
foreach ($unusedTranslationsKeys as $unusedTranslationsKey) {
// Dont show through errors for the skippable start or end keys
if(Str::startsWith($unusedTranslationsKey, $this->skippableStartKeys)) continue;
if(Str::startsWith('KMS::' . $unusedTranslationsKey, $this->skippableStartKeys)) continue;
if(Str::endsWith($unusedTranslationsKey, $this->skippableEndKeys)) continue;
$unusedTranslationErrors->push((object) [
'message' => 'The translation key "' . $unusedTranslationsKey .'" is not used within the application. If this is not correct and if used in a undetectable way, then exclude it from this test.',
]);
}
if($unusedTranslationErrors->isNotEmpty()) {
echo PHP_EOL;
foreach ($unusedTranslationErrors as $unusedTranslationError) echo $unusedTranslationError->message . PHP_EOL;
echo PHP_EOL;
$this->assertEmpty($unusedTranslationErrors->count(), 'Not defined translations are used in the application or you should extends skippable keys.');
}
}
/**
* Map all the files out of the index into the file list
*
* @param array $fileList
* @param string $directoryPath
*/
private function addFilesContainLanguageFunctionsOutOfDirectory(array &$fileList, string $directoryPath)
{
// echo 'Directory indexed: "' . $directoryPath . '"' . PHP_EOL;
$directory = new \DirectoryIterator($directoryPath);
foreach ($directory as $file) {
// Exclude itself
if($file->isDot()) continue;
// If directory then search within that directory
if($file->isDir()) {
$this->addFilesContainLanguageFunctionsOutOfDirectory($fileList, $file->getPathname());
continue;
}
$fileContent = file_get_contents($file->getPathname());
if(!Str::contains($fileContent, ['__(', 'trans(', '@lang('])) continue;
// echo 'File added that contains translation function: "' . $file->getPathname() . '"' . PHP_EOL ;
$fileList[] = $file->getPathname();
}
}
/**
* Generate a list of used translations
*
* @param array $fileList
* @return array
*/
private function createUsedTranslationKeysList(array $fileList): array
{
$usedTranslationKeys = [];
foreach ($fileList as $localizedFile)
{
$fileContent = file_get_contents($localizedFile);
foreach ($this->languageFunctionPatterns as $pattern) {
preg_match_all($pattern, $fileContent, $matches);
$usedTranslationKeys = array_merge($usedTranslationKeys, $matches[1]);
}
}
return $usedTranslationKeys;
}
}