diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml
index 829b83b..b936463 100644
--- a/.github/workflows/run-tests.yml
+++ b/.github/workflows/run-tests.yml
@@ -2,7 +2,7 @@ name: run-tests
-on: [pull_request]
+on: [ pull_request ]
jobs:
build:
@@ -10,8 +10,8 @@ jobs:
strategy:
fail-fast: false
matrix:
- php: [8.3, 8.2]
- laravel: [11.*]
+ php: [ 8.3, 8.2 ]
+ laravel: [ 11.* ]
dependency-version: [ prefer-lowest, prefer-stable ]
include:
- laravel: 11.*
diff --git a/src/TranslationsManager.php b/src/TranslationsManager.php
index e069dc5..e8d83df 100644
--- a/src/TranslationsManager.php
+++ b/src/TranslationsManager.php
@@ -78,19 +78,20 @@ public function getTranslations(string $locale): array
->when($this->filesystem->exists(lang_path($rootFileName)), function ($collection) use ($rootFileName) {
return $collection->prepend($rootFileName);
})
- ->filter(function ($file) {
+ ->filter(function ($file) use ($locale) {
foreach (config('translations.exclude_files') as $excludeFile) {
- if (fnmatch($excludeFile, $file)) {
- return false;
- }
- if (fnmatch($excludeFile, basename($file))) {
+
+ /**
+ *
File exclusion by wildcard
+ * $file is with language like en/book/create.php
while $excludedFile contains only wildcards or path like book/create.php
+ * So, we need to remove the language part from $file before comparing with $excludeFile
+ */
+ if (fnmatch($excludeFile, str_replace($locale.'/', '', $file))) {
return false;
}
-
- return true;
}
- return ! in_array($file, config('translations.exclude_files'));
+ return true;
})
->filter(function ($file) {
return $this->filesystem->extension($file) == 'php' || $this->filesystem->extension($file) == 'json';
@@ -112,6 +113,36 @@ public function getTranslations(string $locale): array
return $translations;
}
+ public function download(): ?string
+ {
+ try {
+ $this->export(download: true);
+
+ $zip = new ZipArchive();
+
+ $zipPath = storage_path('app/lang.zip');
+ $zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE);
+
+ $baseDir = storage_path('app/translations');
+ $zip->addEmptyDir('lang');
+
+ $files = $this->filesystem->allFiles($baseDir);
+
+ foreach ($files as $file) {
+ $relativePath = str_replace($baseDir.DIRECTORY_SEPARATOR, '', $file->getPathname());
+ $zip->addFile($file->getPathname(), 'lang/'.$relativePath);
+ }
+
+ $zip->close();
+
+ return $zipPath;
+ } catch (Exception $e) {
+ logger()->error($e->getMessage());
+
+ return null;
+ }
+ }
+
public function export($download = false): void
{
$translations = Translation::with('phrases')->get();
@@ -150,34 +181,4 @@ public function export($download = false): void
}
}
}
-
- public function download(): ?string
- {
- try {
- $this->export(download: true);
-
- $zip = new ZipArchive();
-
- $zipPath = storage_path('app/lang.zip');
- $zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE);
-
- $baseDir = storage_path('app/translations');
- $zip->addEmptyDir('lang');
-
- $files = $this->filesystem->allFiles($baseDir);
-
- foreach ($files as $file) {
- $relativePath = str_replace($baseDir.DIRECTORY_SEPARATOR, '', $file->getPathname());
- $zip->addFile($file->getPathname(), 'lang/'.$relativePath);
- }
-
- $zip->close();
-
- return $zipPath;
- } catch (Exception $e) {
- logger()->error($e->getMessage());
-
- return null;
- }
- }
}
diff --git a/tests/TranslationsManagerTest.php b/tests/TranslationsManagerTest.php
index 13ea9af..35d37ab 100644
--- a/tests/TranslationsManagerTest.php
+++ b/tests/TranslationsManagerTest.php
@@ -24,6 +24,9 @@
createPhpLanguageFile('de/validation.php', []);
+ // Create nested folder structure
+ createPhpLanguageFile('en/book/create.php', []);
+
$translationsManager = new TranslationsManager(new Filesystem());
$locales = $translationsManager->getLocales();
@@ -41,7 +44,16 @@
'title' => 'My title',
]);
- Config::set('translations.exclude_files', ['validation.php']);
+ // Update to include nested folder
+ createPhpLanguageFile('en/book/create.php', [
+ 'nested' => 'Nested test',
+ ]);
+
+ createPhpLanguageFile('en/book/excluded.php', [
+ 'nested' => 'Nested test',
+ ]);
+
+ Config::set('translations.exclude_files', ['validation.php', 'book/excluded.php']);
Config::set('translations.source_language', 'en');
$filesystem = new Filesystem();
@@ -50,12 +62,14 @@
expect($translations)->toBe([
'en.json' => ['title' => 'My title'],
'en/auth.php' => ['test' => 'Test'],
+ 'en/book/create.php' => ['nested' => 'Nested test'],
]);
$translations = $translationsManager->getTranslations('');
expect($translations)->toBe([
'en.json' => ['title' => 'My title'],
'en/auth.php' => ['test' => 'Test'],
+ 'en/book/create.php' => ['nested' => 'Nested test'],
]);
});
@@ -70,6 +84,11 @@
'title' => 'My title',
]);
+ // Update to include nested folder
+ createPhpLanguageFile('en/book/create.php', [
+ 'nested' => 'Nested test',
+ ]);
+
Config::set('translations.exclude_files', ['*.php']);
Config::set('translations.source_language', 'en');
$filesystem = new Filesystem();
@@ -89,6 +108,8 @@
test('export creates a new translation file with the correct content', function () {
$filesystem = new Filesystem();
createDirectoryIfNotExits(lang_path('en/auth.php'));
+ // Update to include nested folder
+ createDirectoryIfNotExits(lang_path('en/book/create.php'));
$translation = Translation::factory([
'source' => true,
@@ -104,16 +125,35 @@
]),
]))->create();
+ $nestedTranslation = Translation::factory([
+ 'source' => true,
+ 'language_id' => Language::factory([
+ 'code' => 'en',
+ 'name' => 'English',
+ ]),
+ ])->has(Phrase::factory()->state([
+ 'phrase_id' => null,
+ 'translation_file_id' => TranslationFile::factory([
+ 'name' => 'book/create',
+ 'extension' => 'php',
+ ]),
+ ]))->create();
+
$translationsManager = new TranslationsManager($filesystem);
$translationsManager->export();
$fileName = lang_path('en/'.$translation->phrases[0]->file->name.'.'.$translation->phrases[0]->file->extension);
+ $nestedFileName = lang_path('en/'.$nestedTranslation->phrases[0]->file->name.'.'.$nestedTranslation->phrases[0]->file->extension);
$fileNameInDisk = File::allFiles(lang_path($translation->language->code))[0]->getPathname();
+ $nestedFileNameInDisk = File::allFiles(lang_path($nestedTranslation->language->code))[1]->getPathname();
expect($fileName)->toBe($fileNameInDisk)
->and(File::get($fileName))
- ->toBe("phrases->pluck('value', 'key')->toArray(), VarExporter::TRAILING_COMMA_IN_ARRAY).';'.PHP_EOL);
+ ->toBe("phrases->pluck('value', 'key')->toArray(), VarExporter::TRAILING_COMMA_IN_ARRAY).';'.PHP_EOL)
+ ->and($nestedFileName)->toBe($nestedFileNameInDisk)
+ ->and(File::get($nestedFileName))
+ ->toBe("phrases->pluck('value', 'key')->toArray(), VarExporter::TRAILING_COMMA_IN_ARRAY).';'.PHP_EOL);
File::deleteDirectory(lang_path());
});
@@ -121,6 +161,9 @@
test('export can handle PHP translation files', function () {
createPhpLanguageFile('en/test.php', ['accepted' => 'The :attribute must be accepted.']);
+ // Update to include nested folder
+ createPhpLanguageFile('en/book/create.php', ['nested' => 'Nested :attribute must be accepted.']);
+
$filesystem = new Filesystem();
$translation = Translation::factory()
@@ -134,19 +177,36 @@
->for(Language::factory()->state(['code' => 'en']))
->create();
+ $nestedTranslation = Translation::factory()
+ ->has(Phrase::factory()
+ ->for(TranslationFile::factory()->state(['name' => 'book/create', 'extension' => 'php']), 'file')
+ ->state([
+ 'key' => 'nested',
+ 'value' => 'Nested :attribute must be accepted.',
+ 'phrase_id' => null,
+ ]))
+ ->for(Language::factory()->state(['code' => 'en']))
+ ->create();
+
$translationsManager = new TranslationsManager($filesystem);
$translationsManager->export();
$path = lang_path('en'.DIRECTORY_SEPARATOR.'test.php');
+ $nestedPath = lang_path('en'.DIRECTORY_SEPARATOR.'book'.DIRECTORY_SEPARATOR.'create.php');
$pathInDisk = lang_path($translation->language->code.DIRECTORY_SEPARATOR.'test.php');
+ $nestedPathInDisk = lang_path($nestedTranslation->language->code.DIRECTORY_SEPARATOR.'book'.DIRECTORY_SEPARATOR.'create.php');
- expect(File::get($path))->toBe(File::get($pathInDisk));
+ expect(File::get($path))->toBe(File::get($pathInDisk))
+ ->and(File::get($nestedPath))->toBe(File::get($nestedPathInDisk));
File::deleteDirectory(lang_path());
});
test('export can handle JSON translation files', function () {
createJsonLanguageFile('en/test.json', ['accepted' => 'The :attribute must be accepted.']);
+
+ // Update to include nested folder
+ createJsonLanguageFile('en/book/create.json', ['nested' => 'Nested test']);
$filesystem = new Filesystem();
$translation = Translation::factory()
@@ -160,13 +220,27 @@
->for(Language::factory()->state(['code' => 'en']))
->create();
+ $nestedTranslation = Translation::factory()
+ ->has(Phrase::factory()
+ ->for(TranslationFile::factory()->state(['name' => 'book/create', 'extension' => 'json']), 'file')
+ ->state([
+ 'key' => 'nested',
+ 'value' => 'Nested test',
+ 'phrase_id' => null,
+ ]))
+ ->for(Language::factory()->state(['code' => 'en']))
+ ->create();
+
$translationsManager = new TranslationsManager($filesystem);
$translationsManager->export();
$path = lang_path('en'.DIRECTORY_SEPARATOR.'test.json');
+ $nestedPath = lang_path('en'.DIRECTORY_SEPARATOR.'book'.DIRECTORY_SEPARATOR.'create.json');
$pathInDisk = lang_path($translation->language->code.DIRECTORY_SEPARATOR.'test.json');
+ $nestedPathInDisk = lang_path($nestedTranslation->language->code.DIRECTORY_SEPARATOR.'book'.DIRECTORY_SEPARATOR.'create.json');
- expect(File::get($path))->toBe(File::get($pathInDisk));
+ expect(File::get($path))->toBe(File::get($pathInDisk))
+ ->and(File::get($nestedPath))->toBe(File::get($nestedPathInDisk));
File::deleteDirectory(lang_path());
});