first commit

This commit is contained in:
2025-07-18 16:20:14 +07:00
commit 98af45c018
16382 changed files with 3148096 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
<?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\Intl\Data\Util;
use Symfony\Component\Intl\Exception\BadMethodCallException;
/**
* Work-around for a bug in PHP's \ResourceBundle implementation.
*
* More information can be found on https://bugs.php.net/64356.
* This class can be removed once that bug is fixed.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
class ArrayAccessibleResourceBundle implements \ArrayAccess, \IteratorAggregate, \Countable
{
private \ResourceBundle $bundleImpl;
public function __construct(\ResourceBundle $bundleImpl)
{
$this->bundleImpl = $bundleImpl;
}
public function get(int|string $offset): mixed
{
$value = $this->bundleImpl->get($offset);
return $value instanceof \ResourceBundle ? new static($value) : $value;
}
public function offsetExists(mixed $offset): bool
{
return null !== $this->bundleImpl->get($offset);
}
public function offsetGet(mixed $offset): mixed
{
return $this->get($offset);
}
public function offsetSet(mixed $offset, mixed $value): void
{
throw new BadMethodCallException('Resource bundles cannot be modified.');
}
public function offsetUnset(mixed $offset): void
{
throw new BadMethodCallException('Resource bundles cannot be modified.');
}
public function getIterator(): \Traversable
{
return $this->bundleImpl;
}
public function count(): int
{
return $this->bundleImpl->count();
}
public function getErrorCode(): int
{
return $this->bundleImpl->getErrorCode();
}
public function getErrorMessage(): string
{
return $this->bundleImpl->getErrorMessage();
}
}

View File

@@ -0,0 +1,99 @@
<?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\Intl\Data\Util;
/**
* Scans a directory with data files for locales.
*
* The name of each file with the extension ".txt" is considered, if it "looks"
* like a locale:
*
* - the name must start with two letters;
* - the two letters may optionally be followed by an underscore and any
* sequence of other symbols.
*
* For example, "de" and "de_DE" are considered to be locales. "root" and "meta"
* are not.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
class LocaleScanner
{
/**
* Returns all locales found in the given directory.
*
* @return array An array of locales. The result also contains locales that
* are in fact just aliases for other locales. Use
* {@link scanAliases()} to determine which of the locales
* are aliases
*/
public function scanLocales(string $sourceDir): array
{
$locales = glob($sourceDir.'/*.txt', \GLOB_NOSORT);
// Remove file extension and sort
array_walk($locales, function (&$locale) { $locale = basename($locale, '.txt'); });
// Remove non-locales
$locales = array_filter($locales, fn ($locale) => preg_match('/^[a-z]{2}(_.+)?$/', $locale));
sort($locales);
return $locales;
}
/**
* Returns all locale aliases found in the given directory.
*
* @return array An array with the locale aliases as keys and the aliased
* locales as values
*/
public function scanAliases(string $sourceDir): array
{
$locales = $this->scanLocales($sourceDir);
$aliases = [];
// Delete locales that are no aliases
foreach ($locales as $locale) {
$content = file_get_contents($sourceDir.'/'.$locale.'.txt');
// Aliases contain the text "%%ALIAS" followed by the aliased locale
if (preg_match('/"%%ALIAS"\{"([^"]+)"\}/', $content, $matches)) {
$aliases[$locale] = $matches[1];
}
}
return $aliases;
}
/**
* Returns all locale parents found in the given directory.
*/
public function scanParents(string $sourceDir): array
{
$locales = $this->scanLocales($sourceDir);
$fallbacks = [];
foreach ($locales as $locale) {
$content = file_get_contents($sourceDir.'/'.$locale.'.txt');
// Aliases contain the text "%%PARENT" followed by the aliased locale
if (preg_match('/%%Parent{"([^"]+)"}/', $content, $matches)) {
$fallbacks[$locale] = $matches[1];
}
}
return $fallbacks;
}
}

View File

@@ -0,0 +1,48 @@
<?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\Intl\Data\Util;
use Symfony\Component\Intl\Exception\OutOfBoundsException;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
class RecursiveArrayAccess
{
public static function get(mixed $array, array $indices): mixed
{
foreach ($indices as $index) {
// Use array_key_exists() for arrays, isset() otherwise
if (\is_array($array)) {
if (\array_key_exists($index, $array)) {
$array = $array[$index];
continue;
}
} elseif ($array instanceof \ArrayAccess) {
if (isset($array[$index])) {
$array = $array[$index];
continue;
}
}
throw new OutOfBoundsException(sprintf('The index "%s" does not exist.', $index));
}
return $array;
}
private function __construct()
{
}
}

View File

@@ -0,0 +1,79 @@
<?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\Intl\Data\Util;
use Symfony\Component\Intl\Exception\OutOfBoundsException;
/**
* Implements a ring buffer.
*
* A ring buffer is an array-like structure with a fixed size. If the buffer
* is full, the next written element overwrites the first bucket in the buffer,
* then the second and so on.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @template TKey of array-key
* @template TValue
*
* @implements \ArrayAccess<TKey, TValue>
*
* @internal
*/
class RingBuffer implements \ArrayAccess
{
/** @var array<int, TValue> */
private array $values = [];
/** @var array<TKey, int> */
private array $indices = [];
private int $cursor = 0;
private int $size;
public function __construct(int $size)
{
$this->size = $size;
}
public function offsetExists(mixed $key): bool
{
return isset($this->indices[$key]);
}
public function offsetGet(mixed $key): mixed
{
if (!isset($this->indices[$key])) {
throw new OutOfBoundsException(sprintf('The index "%s" does not exist.', $key));
}
return $this->values[$this->indices[$key]];
}
public function offsetSet(mixed $key, mixed $value): void
{
if (false !== ($keyToRemove = array_search($this->cursor, $this->indices))) {
unset($this->indices[$keyToRemove]);
}
$this->values[$this->cursor] = $value;
$this->indices[$key] = $this->cursor;
$this->cursor = ($this->cursor + 1) % $this->size;
}
public function offsetUnset(mixed $key): void
{
if (isset($this->indices[$key])) {
$this->values[$this->indices[$key]] = null;
unset($this->indices[$key]);
}
}
}