Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Model/Translation.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ public function getTranslation(): string;
public function getToken(): string;

public function getCatalogue(): string;

public function getLocale(): string;
}
20 changes: 11 additions & 9 deletions src/Model/TranslationModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,12 @@
*/
final readonly class TranslationModel implements Translation
{
private string $translation;
private string $token;
private string $catalogue;

public function __construct(string $translation, string $token, string $catalogue)
{
$this->translation = $translation;
$this->token = $token;
$this->catalogue = $catalogue;
public function __construct(
private string $translation,
private string $token,
private string $catalogue,
private string $locale,
) {
}

public function getTranslation(): string
Expand All @@ -34,4 +31,9 @@ public function getCatalogue(): string
{
return $this->catalogue;
}

public function getLocale(): string
{
return $this->locale;
}
}
2 changes: 1 addition & 1 deletion src/Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
interface Repository
{
/** @return Translation[] */
public function findByLocale(string $locale): iterable;
public function fetchTranslations(): iterable;

public function persistCatalogue(MessageCatalogueInterface $catalogue): void;
}
53 changes: 25 additions & 28 deletions src/Translator.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class Translator extends OriginalTranslator implements ResetInterface
private int $version = 0;
private bool $warmUp = false;

private ?array $translations = null;

/**
* @required
*/
Expand All @@ -40,41 +42,35 @@ protected function loadCatalogue(string $locale): void
{
parent::loadCatalogue($locale);

$this->fetchAndMergeTranslations($this->catalogues[$locale]);
}

private function fetchAndMergeTranslations(MessageCatalogueInterface $catalogue): void
{
if ($this->warmUp) {
// do not load translations from database during warmup.
return;
}

$this->fetchTranslations($locale);
}

private function fetchTranslations(string $locale): void
{
$translations = $this->repository?->findByLocale($locale) ?? [];
$catalogue = $this->catalogues[$locale];
foreach ($translations as $translation) {
$catalogue->set(
$translation->getToken(),
$translation->getTranslation(),
$translation->getCatalogue()
);
if ($this->translations === null) {
$this->translations = [];
foreach ($this->repository?->fetchTranslations() ?? [] as $translation) {
$this->translations[$translation->getLocale()][$translation->getCatalogue()][$translation->getToken(
)] = $translation->getTranslation();
}
}
$this->loadFallbackTranslations($catalogue);
}

private function loadFallbackTranslations(MessageCatalogueInterface $catalogue): void
{
while (($catalogue = $catalogue->getFallbackCatalogue()) !== null) {
$translations = $this->repository->findByLocale($catalogue->getLocale());

foreach ($translations as $translation) {
$catalogue->set(
$translation->getToken(),
$translation->getTranslation(),
$translation->getCatalogue()
);
do {
$translations = $this->translations[$catalogue->getLocale()] ?? [];

foreach ($translations as $domain => $messages) {
foreach ($messages as $token => $translation) {
$catalogue->set($token, $translation, $domain);
}
}
}

$catalogue = $catalogue->getFallbackCatalogue();
} while ($catalogue !== null);
}

public function reset(): void
Expand All @@ -85,12 +81,13 @@ public function reset(): void
}

$this->catalogues = [];
$this->translations = null;
$this->version = $version->get();
}

public function warmUp(string $cacheDir, ?string $buildDir = null): array
{
$this->warmUp = true;
$this->warmUp = $buildDir !== null;
try {
return parent::warmUp($cacheDir);
} finally {
Expand Down
17 changes: 16 additions & 1 deletion tests/Integration/Repository/TranslationRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,25 @@ public function __construct(ManagerRegistry $registry)
parent::__construct($registry, Translation::class);
}

public function fetchTranslations(): iterable
{
$qb = $this->createQueryBuilder('translation');
$qb->select(
'NEW '.TranslationModel::class.'(translation.translation, token.token, token.catalogue, language.locale)'
);
$qb->join('translation.token', 'token');
$qb->join('translation.language', 'language');
$query = $qb->getQuery();

return $query->toIterable();
}

public function findByLocale(string $locale): iterable
{
$qb = $this->createQueryBuilder('translation');
$qb->select('NEW ' . TranslationModel::class . '(translation.translation, token.token, token.catalogue)');
$qb->select(
'NEW '.TranslationModel::class.'(translation.translation, token.token, token.catalogue, language.locale)'
);
$qb->join('translation.token', 'token');
$qb->join('translation.language', 'language');
$qb->andWhere('language.locale = :locale')->setParameter('locale', $locale);
Expand Down
23 changes: 14 additions & 9 deletions tests/Integration/TranslatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Symfony\Component\Translation\TranslatorBagInterface;
use Symfony\Contracts\Service\ResetInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use function sprintf;

class TranslatorTest extends KernelTestCase
{
Expand Down Expand Up @@ -179,9 +180,11 @@ public function testCacheFlag(): void
$entityManager->persist($helloWorldInEn);
$entityManager->flush();

if ($translator instanceof ResetInterface) {
$translator->reset();
if (!$translator instanceof ResetInterface) {
throw new \LogicException();
}
$translator->reset();


self::assertSame('Здравей, свят!', $translator->trans('hello_world', locale: 'bg'));
self::assertSame('Hello, world!', $translator->trans('hello_world', locale: 'en'));
Expand All @@ -190,9 +193,7 @@ public function testCacheFlag(): void
$cacheFlag = static::getContainer()->get(CacheFlag::class);
$cacheFlag->increment($cacheFlag->getVersion());

if ($translator instanceof ResetInterface) {
$translator->reset();
}
$translator->reset();

self::assertSame('Здравей, свят! редактирано', $translator->trans('hello_world', locale: 'bg'));
self::assertSame('Hello, world! Edited', $translator->trans('hello_world', locale: 'en'));
Expand Down Expand Up @@ -232,9 +233,12 @@ public function testDeletedTranslation(): void
$cacheFlag = static::getContainer()->get(CacheFlag::class);
$cacheFlag->increment($cacheFlag->getVersion());

if ($translator instanceof ResetInterface) {
$translator->reset();
if (!$translator instanceof ResetInterface) {
throw new \LogicException(
sprintf('"%s" should not implement "%s"', $translator::class, ResetInterface::class)
);
}
$translator->reset();

// deleted BG trans should fallback to EN
self::assertSame('Hello, world!', $translator->trans('hello_world', locale: 'bg'));
Expand Down Expand Up @@ -287,9 +291,10 @@ public function testCatalogues(): void
$cacheFlag = static::getContainer()->get(CacheFlag::class);
$cacheFlag->increment($cacheFlag->getVersion());

if ($translator instanceof ResetInterface) {
$translator->reset();
if (!$translator instanceof ResetInterface) {
throw new \LogicException();
}
$translator->reset();

$catalogue = $translator->getCatalogue('en-gb');

Expand Down
Loading