first commit

This commit is contained in:
Sampanna Rimal
2024-08-27 17:48:06 +05:45
commit 53c0140f58
10839 changed files with 1125847 additions and 0 deletions

View File

@ -0,0 +1,187 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Catalogue;
use Symfony\Component\Translation\Exception\InvalidArgumentException;
use Symfony\Component\Translation\Exception\LogicException;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Component\Translation\MessageCatalogueInterface;
/**
* Base catalogues binary operation class.
*
* A catalogue binary operation performs operation on
* source (the left argument) and target (the right argument) catalogues.
*
* @author Jean-François Simon <contact@jfsimon.fr>
*/
abstract class AbstractOperation implements OperationInterface
{
public const OBSOLETE_BATCH = 'obsolete';
public const NEW_BATCH = 'new';
public const ALL_BATCH = 'all';
protected $source;
protected $target;
protected $result;
/**
* This array stores 'all', 'new' and 'obsolete' messages for all valid domains.
*
* The data structure of this array is as follows:
*
* [
* 'domain 1' => [
* 'all' => [...],
* 'new' => [...],
* 'obsolete' => [...]
* ],
* 'domain 2' => [
* 'all' => [...],
* 'new' => [...],
* 'obsolete' => [...]
* ],
* ...
* ]
*
* @var array The array that stores 'all', 'new' and 'obsolete' messages
*/
protected $messages;
private array $domains;
/**
* @throws LogicException
*/
public function __construct(MessageCatalogueInterface $source, MessageCatalogueInterface $target)
{
if ($source->getLocale() !== $target->getLocale()) {
throw new LogicException('Operated catalogues must belong to the same locale.');
}
$this->source = $source;
$this->target = $target;
$this->result = new MessageCatalogue($source->getLocale());
$this->messages = [];
}
public function getDomains(): array
{
if (!isset($this->domains)) {
$domains = [];
foreach ([$this->source, $this->target] as $catalogue) {
foreach ($catalogue->getDomains() as $domain) {
$domains[$domain] = $domain;
if ($catalogue->all($domainIcu = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX)) {
$domains[$domainIcu] = $domainIcu;
}
}
}
$this->domains = array_values($domains);
}
return $this->domains;
}
public function getMessages(string $domain): array
{
if (!\in_array($domain, $this->getDomains())) {
throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain));
}
if (!isset($this->messages[$domain][self::ALL_BATCH])) {
$this->processDomain($domain);
}
return $this->messages[$domain][self::ALL_BATCH];
}
public function getNewMessages(string $domain): array
{
if (!\in_array($domain, $this->getDomains())) {
throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain));
}
if (!isset($this->messages[$domain][self::NEW_BATCH])) {
$this->processDomain($domain);
}
return $this->messages[$domain][self::NEW_BATCH];
}
public function getObsoleteMessages(string $domain): array
{
if (!\in_array($domain, $this->getDomains())) {
throw new InvalidArgumentException(sprintf('Invalid domain: "%s".', $domain));
}
if (!isset($this->messages[$domain][self::OBSOLETE_BATCH])) {
$this->processDomain($domain);
}
return $this->messages[$domain][self::OBSOLETE_BATCH];
}
public function getResult(): MessageCatalogueInterface
{
foreach ($this->getDomains() as $domain) {
if (!isset($this->messages[$domain])) {
$this->processDomain($domain);
}
}
return $this->result;
}
/**
* @param self::*_BATCH $batch
*/
public function moveMessagesToIntlDomainsIfPossible(string $batch = self::ALL_BATCH): void
{
// If MessageFormatter class does not exists, intl domains are not supported.
if (!class_exists(\MessageFormatter::class)) {
return;
}
foreach ($this->getDomains() as $domain) {
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
$messages = match ($batch) {
self::OBSOLETE_BATCH => $this->getObsoleteMessages($domain),
self::NEW_BATCH => $this->getNewMessages($domain),
self::ALL_BATCH => $this->getMessages($domain),
default => throw new \InvalidArgumentException(sprintf('$batch argument must be one of ["%s", "%s", "%s"].', self::ALL_BATCH, self::NEW_BATCH, self::OBSOLETE_BATCH)),
};
if (!$messages || (!$this->source->all($intlDomain) && $this->source->all($domain))) {
continue;
}
$result = $this->getResult();
$allIntlMessages = $result->all($intlDomain);
$currentMessages = array_diff_key($messages, $result->all($domain));
$result->replace($currentMessages, $domain);
$result->replace($allIntlMessages + $messages, $intlDomain);
}
}
/**
* Performs operation on source and target catalogues for the given domain and
* stores the results.
*
* @param string $domain The domain which the operation will be performed for
*
* @return void
*/
abstract protected function processDomain(string $domain);
}

View File

@ -0,0 +1,72 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Catalogue;
use Symfony\Component\Translation\MessageCatalogueInterface;
/**
* Merge operation between two catalogues as follows:
* all = source target = {x: x ∈ source x ∈ target}
* new = all source = {x: x ∈ target ∧ x ∉ source}
* obsolete = source all = {x: x ∈ source ∧ x ∉ source ∧ x ∉ target} = ∅
* Basically, the result contains messages from both catalogues.
*
* @author Jean-François Simon <contact@jfsimon.fr>
*/
class MergeOperation extends AbstractOperation
{
/**
* @return void
*/
protected function processDomain(string $domain)
{
$this->messages[$domain] = [
'all' => [],
'new' => [],
'obsolete' => [],
];
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
foreach ($this->target->getCatalogueMetadata('', $domain) ?? [] as $key => $value) {
if (null === $this->result->getCatalogueMetadata($key, $domain)) {
$this->result->setCatalogueMetadata($key, $value, $domain);
}
}
foreach ($this->target->getCatalogueMetadata('', $intlDomain) ?? [] as $key => $value) {
if (null === $this->result->getCatalogueMetadata($key, $intlDomain)) {
$this->result->setCatalogueMetadata($key, $value, $intlDomain);
}
}
foreach ($this->source->all($domain) as $id => $message) {
$this->messages[$domain]['all'][$id] = $message;
$d = $this->source->defines($id, $intlDomain) ? $intlDomain : $domain;
$this->result->add([$id => $message], $d);
if (null !== $keyMetadata = $this->source->getMetadata($id, $d)) {
$this->result->setMetadata($id, $keyMetadata, $d);
}
}
foreach ($this->target->all($domain) as $id => $message) {
if (!$this->source->has($id, $domain)) {
$this->messages[$domain]['all'][$id] = $message;
$this->messages[$domain]['new'][$id] = $message;
$d = $this->target->defines($id, $intlDomain) ? $intlDomain : $domain;
$this->result->add([$id => $message], $d);
if (null !== $keyMetadata = $this->target->getMetadata($id, $d)) {
$this->result->setMetadata($id, $keyMetadata, $d);
}
}
}
}
}

View File

@ -0,0 +1,61 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Catalogue;
use Symfony\Component\Translation\MessageCatalogueInterface;
/**
* Represents an operation on catalogue(s).
*
* An instance of this interface performs an operation on one or more catalogues and
* stores intermediate and final results of the operation.
*
* The first catalogue in its argument(s) is called the 'source catalogue' or 'source' and
* the following results are stored:
*
* Messages: also called 'all', are valid messages for the given domain after the operation is performed.
*
* New Messages: also called 'new' (new = all source = {x: x ∈ all ∧ x ∉ source}).
*
* Obsolete Messages: also called 'obsolete' (obsolete = source all = {x: x ∈ source ∧ x ∉ all}).
*
* Result: also called 'result', is the resulting catalogue for the given domain that holds the same messages as 'all'.
*
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
*/
interface OperationInterface
{
/**
* Returns domains affected by operation.
*/
public function getDomains(): array;
/**
* Returns all valid messages ('all') after operation.
*/
public function getMessages(string $domain): array;
/**
* Returns new messages ('new') after operation.
*/
public function getNewMessages(string $domain): array;
/**
* Returns obsolete messages ('obsolete') after operation.
*/
public function getObsoleteMessages(string $domain): array;
/**
* Returns resulting catalogue ('result').
*/
public function getResult(): MessageCatalogueInterface;
}

View File

@ -0,0 +1,86 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Translation\Catalogue;
use Symfony\Component\Translation\MessageCatalogueInterface;
/**
* Target operation between two catalogues:
* intersection = source ∩ target = {x: x ∈ source ∧ x ∈ target}
* all = intersection (target intersection) = target
* new = all source = {x: x ∈ target ∧ x ∉ source}
* obsolete = source all = source target = {x: x ∈ source ∧ x ∉ target}
* Basically, the result contains messages from the target catalogue.
*
* @author Michael Lee <michael.lee@zerustech.com>
*/
class TargetOperation extends AbstractOperation
{
/**
* @return void
*/
protected function processDomain(string $domain)
{
$this->messages[$domain] = [
'all' => [],
'new' => [],
'obsolete' => [],
];
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
foreach ($this->target->getCatalogueMetadata('', $domain) ?? [] as $key => $value) {
if (null === $this->result->getCatalogueMetadata($key, $domain)) {
$this->result->setCatalogueMetadata($key, $value, $domain);
}
}
foreach ($this->target->getCatalogueMetadata('', $intlDomain) ?? [] as $key => $value) {
if (null === $this->result->getCatalogueMetadata($key, $intlDomain)) {
$this->result->setCatalogueMetadata($key, $value, $intlDomain);
}
}
// For 'all' messages, the code can't be simplified as ``$this->messages[$domain]['all'] = $target->all($domain);``,
// because doing so will drop messages like {x: x ∈ source ∧ x ∉ target.all ∧ x ∈ target.fallback}
//
// For 'new' messages, the code can't be simplified as ``array_diff_assoc($this->target->all($domain), $this->source->all($domain));``
// because doing so will not exclude messages like {x: x ∈ target ∧ x ∉ source.all ∧ x ∈ source.fallback}
//
// For 'obsolete' messages, the code can't be simplified as ``array_diff_assoc($this->source->all($domain), $this->target->all($domain))``
// because doing so will not exclude messages like {x: x ∈ source ∧ x ∉ target.all ∧ x ∈ target.fallback}
foreach ($this->source->all($domain) as $id => $message) {
if ($this->target->has($id, $domain)) {
$this->messages[$domain]['all'][$id] = $message;
$d = $this->source->defines($id, $intlDomain) ? $intlDomain : $domain;
$this->result->add([$id => $message], $d);
if (null !== $keyMetadata = $this->source->getMetadata($id, $d)) {
$this->result->setMetadata($id, $keyMetadata, $d);
}
} else {
$this->messages[$domain]['obsolete'][$id] = $message;
}
}
foreach ($this->target->all($domain) as $id => $message) {
if (!$this->source->has($id, $domain)) {
$this->messages[$domain]['all'][$id] = $message;
$this->messages[$domain]['new'][$id] = $message;
$d = $this->target->defines($id, $intlDomain) ? $intlDomain : $domain;
$this->result->add([$id => $message], $d);
if (null !== $keyMetadata = $this->target->getMetadata($id, $d)) {
$this->result->setMetadata($id, $keyMetadata, $d);
}
}
}
}
}