-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from esign/feature/import-command
Add: command to import translations from files to the database
- Loading branch information
Showing
7 changed files
with
280 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<?php | ||
|
||
namespace Esign\TranslationLoader\Actions; | ||
|
||
use Esign\TranslationLoader\TranslationLoaderServiceProvider; | ||
use Illuminate\Support\Facades\DB; | ||
use Illuminate\Translation\FileLoader; | ||
|
||
class ImportFileTranslationsToDatabaseAction | ||
{ | ||
protected FileLoader $fileLoader; | ||
|
||
public function __construct() | ||
{ | ||
$this->fileLoader = new FileLoader(app('files'), app('path.lang')); | ||
} | ||
|
||
public function handle(array $locales, bool $overwrite): int | ||
{ | ||
return $this->upsertOrInsertTranslations($this->getTranslations($locales), $overwrite); | ||
} | ||
|
||
protected function getTranslations(array $locales): array | ||
{ | ||
$groupedTranslations = []; | ||
foreach ($locales as $locale) { | ||
$translations = $this->fileLoader->load($locale, '*', '*'); | ||
foreach ($translations as $key => $value) { | ||
$groupedTranslations[$key][$locale] = $value; | ||
} | ||
} | ||
|
||
return $this->normalizeTranslations($groupedTranslations, $locales); | ||
} | ||
|
||
protected function normalizeTranslations(array $translations, array $locales): array | ||
{ | ||
foreach ($translations as &$translation) { | ||
foreach ($locales as $locale) { | ||
if (! isset($translation[$locale])) { | ||
$translation[$locale] = null; | ||
} | ||
} | ||
} | ||
|
||
return $translations; | ||
} | ||
|
||
protected function prepareTranslationsForUpsert(array $translations): array | ||
{ | ||
/** @var \Esign\TranslationLoader\Models\Translation */ | ||
$configuredModelClass = TranslationLoaderServiceProvider::getConfiguredModel(); | ||
|
||
$preparedTranslations = []; | ||
foreach ($translations as $key => $values) { | ||
$translation = new $configuredModelClass(); | ||
$translation->group = '*'; | ||
$translation->key = $key; | ||
$translation->created_at = now()->toDateTimeString(); | ||
$translation->updated_at = now()->toDateTimeString(); | ||
$translation->setTranslations('value', $values); | ||
$preparedTranslations[] = $translation->getAttributes(); | ||
} | ||
|
||
return $preparedTranslations; | ||
} | ||
|
||
protected function upsertOrInsertTranslations(array $translations, bool $overwrite): int | ||
{ | ||
/** @var \Esign\TranslationLoader\Models\Translation */ | ||
$configuredModelClass = TranslationLoaderServiceProvider::getConfiguredModel(); | ||
$translations = $this->prepareTranslationsForUpsert($translations); | ||
$affectedRecords = 0; | ||
|
||
DB::transaction(function () use ($translations, $configuredModelClass, $overwrite, &$affectedRecords) { | ||
foreach (array_chunk($translations, 500, true) as $chunk) { | ||
if ($overwrite) { | ||
$affectedRecords += $configuredModelClass::query()->upsert($chunk, ['key', 'group']); | ||
} else { | ||
$affectedRecords += $configuredModelClass::query()->insertOrIgnore($chunk); | ||
} | ||
} | ||
}); | ||
|
||
return $affectedRecords; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php | ||
|
||
namespace Esign\TranslationLoader\Commands; | ||
|
||
use Esign\TranslationLoader\Actions\ImportFileTranslationsToDatabaseAction; | ||
use Illuminate\Console\Command; | ||
|
||
class ImportFileTranslationsToDatabaseCommand extends Command | ||
{ | ||
protected $signature = 'translations:import-files-to-database {--locales=} {--overwrite}'; | ||
protected $description = 'Imports file translations to the database.'; | ||
|
||
public function handle(ImportFileTranslationsToDatabaseAction $importFileTranslationsToDatabaseAction): int | ||
{ | ||
$affectedRecords = $importFileTranslationsToDatabaseAction->handle( | ||
locales: explode(',', $this->option('locales')), | ||
overwrite: (bool) $this->option('overwrite'), | ||
); | ||
|
||
$this->info("Successfully imported translations, affected records: {$affectedRecords}."); | ||
|
||
return self::SUCCESS; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
144 changes: 144 additions & 0 deletions
144
tests/Feature/Commands/ImportFileTranslationToDatabaseCommandTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
<?php | ||
|
||
namespace Esign\TranslationLoader\Tests\Feature\Commands; | ||
|
||
use Esign\TranslationLoader\Commands\ImportFileTranslationsToDatabaseCommand; | ||
use Esign\TranslationLoader\Models\Translation; | ||
use Esign\TranslationLoader\Tests\TestCase; | ||
|
||
class ImportFileTranslationToDatabaseCommandTest extends TestCase | ||
{ | ||
/** @test */ | ||
public function it_can_import_translations() | ||
{ | ||
$this->artisan(ImportFileTranslationsToDatabaseCommand::class, ['--locales' => 'en,nl']); | ||
|
||
$this->assertDatabaseHas(Translation::class, [ | ||
'group' => '*', | ||
'key' => 'Hello world', | ||
'value_en' => 'Hello world', | ||
'value_nl' => 'Hallo wereld', | ||
]); | ||
} | ||
|
||
/** @test */ | ||
public function it_can_import_translations_for_specific_locales() | ||
{ | ||
$this->artisan(ImportFileTranslationsToDatabaseCommand::class, ['--locales' => 'en']); | ||
|
||
$this->assertDatabaseHas(Translation::class, [ | ||
'group' => '*', | ||
'key' => 'Hello world', | ||
'value_en' => 'Hello world', | ||
'value_nl' => null, | ||
]); | ||
} | ||
|
||
/** @test */ | ||
public function it_wont_overwrite_existing_translations_when_the_overwrite_flag_was_not_given() | ||
{ | ||
Translation::create([ | ||
'group' => '*', | ||
'key' => 'Hello world', | ||
'value_en' => 'Goodbye world', | ||
'value_nl' => 'Tot ziens wereld', | ||
]); | ||
|
||
$this->artisan(ImportFileTranslationsToDatabaseCommand::class, ['--locales' => 'en,nl']); | ||
|
||
$this->assertDatabaseHas(Translation::class, [ | ||
'group' => '*', | ||
'key' => 'Hello world', | ||
'value_en' => 'Goodbye world', | ||
'value_nl' => 'Tot ziens wereld', | ||
]); | ||
} | ||
|
||
/** @test */ | ||
public function it_can_overwrite_existing_translations() | ||
{ | ||
Translation::create([ | ||
'group' => '*', | ||
'key' => 'Hello world', | ||
'value_en' => 'Goodbye world', | ||
'value_nl' => 'Tot ziens wereld', | ||
]); | ||
|
||
$this->artisan(ImportFileTranslationsToDatabaseCommand::class, ['--locales' => 'en,nl', '--overwrite' => true]); | ||
|
||
$this->assertDatabaseHas(Translation::class, [ | ||
'group' => '*', | ||
'key' => 'Hello world', | ||
'value_en' => 'Hello world', | ||
'value_nl' => 'Hallo wereld', | ||
]); | ||
} | ||
|
||
/** @test */ | ||
public function it_wont_overwrite_existing_translations_for_locales_that_were_not_specified() | ||
{ | ||
Translation::create([ | ||
'group' => '*', | ||
'key' => 'Hello world', | ||
'value_en' => 'Goodbye world', | ||
'value_nl' => 'Tot ziens wereld', | ||
]); | ||
|
||
$this->artisan(ImportFileTranslationsToDatabaseCommand::class, ['--locales' => 'en', '--overwrite' => true]); | ||
|
||
$this->assertDatabaseHas(Translation::class, [ | ||
'group' => '*', | ||
'key' => 'Hello world', | ||
'value_en' => 'Hello world', | ||
'value_nl' => 'Tot ziens wereld', | ||
]); | ||
} | ||
|
||
/** @test */ | ||
public function it_can_report_the_affected_records() | ||
{ | ||
$command = $this->artisan(ImportFileTranslationsToDatabaseCommand::class, ['--locales' => 'en']); | ||
|
||
$command->expectsOutputToContain('Successfully imported translations, affected records: 1.'); | ||
$command->assertSuccessful(); | ||
} | ||
|
||
/** @test */ | ||
public function it_can_report_the_affected_records_when_a_translation_is_already_present() | ||
{ | ||
Translation::create([ | ||
'group' => '*', | ||
'key' => 'Hello world', | ||
'value_en' => 'Hello world', | ||
]); | ||
|
||
$command = $this->artisan(ImportFileTranslationsToDatabaseCommand::class, ['--locales' => 'en']); | ||
|
||
$command->expectsOutputToContain('Successfully imported translations, affected records: 0.'); | ||
$command->assertSuccessful(); | ||
} | ||
|
||
/** @test */ | ||
public function it_can_report_affected_records_when_the_overwrite_flag_is_given() | ||
{ | ||
$command = $this->artisan(ImportFileTranslationsToDatabaseCommand::class, ['--locales' => 'en', '--overwrite' => true]); | ||
|
||
$command->expectsOutputToContain('Successfully imported translations, affected records: 1.'); | ||
$command->assertSuccessful(); | ||
} | ||
|
||
/** @test */ | ||
public function it_can_report_affected_records_when_the_overwrite_flag_is_given_and_a_translation_is_already_present() | ||
{ | ||
Translation::create([ | ||
'group' => '*', | ||
'key' => 'Hello world', | ||
'value_en' => 'Hello world', | ||
]); | ||
|
||
$command = $this->artisan(ImportFileTranslationsToDatabaseCommand::class, ['--locales' => 'en', '--overwrite' => true]); | ||
|
||
$command->expectsOutputToContain('Successfully imported translations, affected records: 1.'); | ||
$command->assertSuccessful(); | ||
} | ||
} |