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,58 @@
CHANGELOG
=========
6.4
---
* Add support for ISO-3166-1 numeric codes with `Countries::getNumericCode()`, `Countries::getNumericCodes()`,
`Countries::numericCodeExists()` and `Countries::getAlpha2FromNumeric()`
6.3
---
* Add the special `strip` locale to `EmojiTransliterator` to strip all emojis from a string
* Add `compress` script to compress the `Resources/data` directory when disk space matters
6.2
---
* Add `EmojiTransliterator` to translate emoji to many locales
6.0
---
* Remove `DateFormatter\*`, `Collator`, `NumberFormatter`, `Locale`, `IntlGlobals`, `MethodArgumentNotImplementedException`, `MethodArgumentValueNotImplementedException`, `MethodNotImplementedException`and `NotImplementedException` classes, use symfony/polyfill-intl-icu ^1.21 instead
5.3
---
* Add `Currencies::getCashFractionDigits()` and `Currencies::getCashRoundingIncrement()`
5.0.0
-----
* removed `ResourceBundle` namespace
4.4.0
-----
* excluded language code `root`
* added to both `Countries` and `Languages` the methods `getAlpha3Codes`, `getAlpha3Code`, `getAlpha2Code`, `alpha3CodeExists`, `getAlpha3Name` and `getAlpha3Names`
* excluded localized languages (e.g. `en_US`) from `Languages` in `getLanguageCodes()` and `getNames()`
4.3.0
-----
* deprecated `ResourceBundle` namespace
* added `Currencies` in favor of `Intl::getCurrencyBundle()`
* added `Languages` and `Scripts` in favor of `Intl::getLanguageBundle()`
* added `Locales` in favor of `Intl::getLocaleBundle()`
* added `Countries` in favor of `Intl::getRegionBundle()`
* added `Timezones`
* made country codes ISO 3166 compliant
* excluded script code `Zzzz`
4.2.0
-----
* excluded language codes `mis`, `mul`, `und` and `zxx`

View File

@@ -0,0 +1,177 @@
<?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;
use Symfony\Component\Intl\Exception\MissingResourceException;
/**
* Gives access to region-related ICU data.
*
* @author Bernhard Schussek <bschussek@gmail.com>
* @author Roland Franssen <franssen.roland@gmail.com>
*/
final class Countries extends ResourceBundle
{
/**
* Returns all available countries.
*
* Countries are returned as uppercase ISO 3166 two-letter country codes.
*
* A full table of ISO 3166 country codes can be found here:
* https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes
*
* This list only contains "officially assigned ISO 3166-1 alpha-2" country codes.
*
* @return string[]
*/
public static function getCountryCodes(): array
{
return self::readEntry(['Regions'], 'meta');
}
/**
* Returns all available countries (3 letters).
*
* Countries are returned as uppercase ISO 3166 three-letter country codes.
*
* This list only contains "officially assigned ISO 3166-1 alpha-3" country codes.
*
* @return string[]
*/
public static function getAlpha3Codes(): array
{
return self::readEntry(['Alpha2ToAlpha3'], 'meta');
}
/**
* Returns all available numeric country codes (3 digits).
*
* Countries are returned as ISO 3166 numeric three-digit country codes.
*
* This list only contains "officially assigned ISO 3166-1 numeric" country codes.
*
* Returns an array with Alpha2 country codes as keys, and numeric codes as values.
*
* @return array<string, string>
*/
public static function getNumericCodes(): array
{
return self::readEntry(['Alpha2ToNumeric'], 'meta');
}
public static function getAlpha3Code(string $alpha2Code): string
{
return self::readEntry(['Alpha2ToAlpha3', $alpha2Code], 'meta');
}
public static function getAlpha2Code(string $alpha3Code): string
{
return self::readEntry(['Alpha3ToAlpha2', $alpha3Code], 'meta');
}
public static function getNumericCode(string $alpha2Code): string
{
return self::readEntry(['Alpha2ToNumeric', $alpha2Code], 'meta');
}
public static function getAlpha2FromNumeric(string $numericCode): string
{
// Use an underscore prefix to force numeric strings with leading zeros to remain as strings
return self::readEntry(['NumericToAlpha2', '_'.$numericCode], 'meta');
}
public static function exists(string $alpha2Code): bool
{
try {
self::readEntry(['Names', $alpha2Code]);
return true;
} catch (MissingResourceException) {
return false;
}
}
public static function alpha3CodeExists(string $alpha3Code): bool
{
try {
self::getAlpha2Code($alpha3Code);
return true;
} catch (MissingResourceException) {
return false;
}
}
public static function numericCodeExists(string $numericCode): bool
{
try {
self::getAlpha2FromNumeric($numericCode);
return true;
} catch (MissingResourceException $e) {
return false;
}
}
/**
* Gets the country name from its alpha2 code.
*
* @throws MissingResourceException if the country code does not exist
*/
public static function getName(string $country, ?string $displayLocale = null): string
{
return self::readEntry(['Names', $country], $displayLocale);
}
/**
* Gets the country name from its alpha3 code.
*
* @throws MissingResourceException if the country code does not exist
*/
public static function getAlpha3Name(string $alpha3Code, ?string $displayLocale = null): string
{
return self::getName(self::getAlpha2Code($alpha3Code), $displayLocale);
}
/**
* Gets the list of country names indexed with alpha2 codes as keys.
*
* @return array<string, string>
*/
public static function getNames(?string $displayLocale = null): array
{
return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale);
}
/**
* Gets the list of country names indexed with alpha3 codes as keys.
*
* Same as method getNames, but with alpha3 codes instead of alpha2 codes as keys.
*
* @return array<string, string>
*/
public static function getAlpha3Names(?string $displayLocale = null): array
{
$alpha2Names = self::getNames($displayLocale);
$alpha3Names = [];
foreach ($alpha2Names as $alpha2Code => $name) {
$alpha3Names[self::getAlpha3Code($alpha2Code)] = $name;
}
return $alpha3Names;
}
protected static function getPath(): string
{
return Intl::getDataDirectory().'/'.Intl::REGION_DIR;
}
}

View File

@@ -0,0 +1,146 @@
<?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;
use Symfony\Component\Intl\Exception\MissingResourceException;
/**
* Gives access to currency-related ICU data.
*
* @author Bernhard Schussek <bschussek@gmail.com>
* @author Roland Franssen <franssen.roland@gmail.com>
*/
final class Currencies extends ResourceBundle
{
private const INDEX_SYMBOL = 0;
private const INDEX_NAME = 1;
private const INDEX_FRACTION_DIGITS = 0;
private const INDEX_ROUNDING_INCREMENT = 1;
private const INDEX_CASH_FRACTION_DIGITS = 2;
private const INDEX_CASH_ROUNDING_INCREMENT = 3;
/**
* @return string[]
*/
public static function getCurrencyCodes(): array
{
return self::readEntry(['Currencies'], 'meta');
}
public static function exists(string $currency): bool
{
try {
self::readEntry(['Names', $currency, self::INDEX_NAME]);
return true;
} catch (MissingResourceException) {
return false;
}
}
/**
* @throws MissingResourceException if the currency code does not exist
*/
public static function getName(string $currency, ?string $displayLocale = null): string
{
return self::readEntry(['Names', $currency, self::INDEX_NAME], $displayLocale);
}
/**
* @return string[]
*/
public static function getNames(?string $displayLocale = null): array
{
// ====================================================================
// For reference: It is NOT possible to return names indexed by
// numeric code here, because some numeric codes map to multiple
// 3-letter codes (e.g. 32 => "ARA", "ARP", "ARS")
// ====================================================================
$names = self::readEntry(['Names'], $displayLocale);
if ($names instanceof \Traversable) {
$names = iterator_to_array($names);
}
array_walk($names, function (&$value) {
$value = $value[self::INDEX_NAME];
});
return self::asort($names, $displayLocale);
}
/**
* @throws MissingResourceException if the currency code does not exist
*/
public static function getSymbol(string $currency, ?string $displayLocale = null): string
{
return self::readEntry(['Names', $currency, self::INDEX_SYMBOL], $displayLocale);
}
public static function getFractionDigits(string $currency): int
{
try {
return self::readEntry(['Meta', $currency, self::INDEX_FRACTION_DIGITS], 'meta');
} catch (MissingResourceException) {
return self::readEntry(['Meta', 'DEFAULT', self::INDEX_FRACTION_DIGITS], 'meta');
}
}
public static function getRoundingIncrement(string $currency): int
{
try {
return self::readEntry(['Meta', $currency, self::INDEX_ROUNDING_INCREMENT], 'meta');
} catch (MissingResourceException) {
return self::readEntry(['Meta', 'DEFAULT', self::INDEX_ROUNDING_INCREMENT], 'meta');
}
}
public static function getCashFractionDigits(string $currency): int
{
try {
return self::readEntry(['Meta', $currency, self::INDEX_CASH_FRACTION_DIGITS], 'meta');
} catch (MissingResourceException) {
return self::readEntry(['Meta', 'DEFAULT', self::INDEX_CASH_FRACTION_DIGITS], 'meta');
}
}
public static function getCashRoundingIncrement(string $currency): int
{
try {
return self::readEntry(['Meta', $currency, self::INDEX_CASH_ROUNDING_INCREMENT], 'meta');
} catch (MissingResourceException) {
return self::readEntry(['Meta', 'DEFAULT', self::INDEX_CASH_ROUNDING_INCREMENT], 'meta');
}
}
/**
* @throws MissingResourceException if the currency code has no numeric code
*/
public static function getNumericCode(string $currency): int
{
return self::readEntry(['Alpha3ToNumeric', $currency], 'meta');
}
/**
* @throws MissingResourceException if the numeric code does not exist
*/
public static function forNumericCode(int $numericCode): array
{
return self::readEntry(['NumericToAlpha3', (string) $numericCode], 'meta');
}
protected static function getPath(): string
{
return Intl::getDataDirectory().'/'.Intl::CURRENCY_DIR;
}
}

View File

@@ -0,0 +1,30 @@
<?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\Bundle\Compiler;
/**
* Compiles a resource bundle.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
interface BundleCompilerInterface
{
/**
* Compiles a resource bundle at the given source to the given target
* directory.
*
* @return void
*/
public function compile(string $sourcePath, string $targetDir);
}

View File

@@ -0,0 +1,58 @@
<?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\Bundle\Compiler;
use Symfony\Component\Intl\Exception\RuntimeException;
/**
* Compiles .txt resource bundles to binary .res files.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
class GenrbCompiler implements BundleCompilerInterface
{
private string $genrb;
/**
* Creates a new compiler based on the "genrb" executable.
*
* @param string $genrb Optional. The path to the "genrb" executable
* @param string $envVars Optional. Environment variables to be loaded when running "genrb".
*
* @throws RuntimeException if the "genrb" cannot be found
*/
public function __construct(string $genrb = 'genrb', string $envVars = '')
{
exec('which '.$genrb, $output, $status);
if (0 !== $status) {
throw new RuntimeException(sprintf('The command "%s" is not installed.', $genrb));
}
$this->genrb = ($envVars ? $envVars.' ' : '').$genrb;
}
public function compile(string $sourcePath, string $targetDir): void
{
if (is_dir($sourcePath)) {
$sourcePath .= '/*.txt';
}
exec($this->genrb.' --quiet -e UTF-8 -d '.$targetDir.' '.$sourcePath, $output, $status);
if (0 !== $status) {
throw new RuntimeException(sprintf('genrb failed with status %d while compiling "%s" to "%s".', $status, $sourcePath, $targetDir));
}
}
}

View File

@@ -0,0 +1,43 @@
<?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\Bundle\Reader;
use Symfony\Component\Intl\Data\Util\RingBuffer;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
class BufferedBundleReader implements BundleReaderInterface
{
private BundleReaderInterface $reader;
/** @var RingBuffer<string, mixed> */
private RingBuffer $buffer;
public function __construct(BundleReaderInterface $reader, int $bufferSize)
{
$this->reader = $reader;
$this->buffer = new RingBuffer($bufferSize);
}
public function read(string $path, string $locale): mixed
{
$hash = $path.'//'.$locale;
if (!isset($this->buffer[$hash])) {
$this->buffer[$hash] = $this->reader->read($path, $locale);
}
return $this->buffer[$hash];
}
}

View File

@@ -0,0 +1,171 @@
<?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\Bundle\Reader;
use Symfony\Component\Intl\Data\Util\RecursiveArrayAccess;
use Symfony\Component\Intl\Exception\MissingResourceException;
use Symfony\Component\Intl\Exception\OutOfBoundsException;
use Symfony\Component\Intl\Exception\ResourceBundleNotFoundException;
use Symfony\Component\Intl\Locale;
/**
* Default implementation of {@link BundleEntryReaderInterface}.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @see BundleEntryReaderInterface
*
* @internal
*/
class BundleEntryReader implements BundleEntryReaderInterface
{
private BundleReaderInterface $reader;
/**
* A mapping of locale aliases to locales.
*/
private array $localeAliases = [];
/**
* Creates an entry reader based on the given resource bundle reader.
*/
public function __construct(BundleReaderInterface $reader)
{
$this->reader = $reader;
}
/**
* Stores a mapping of locale aliases to locales.
*
* This mapping is used when reading entries and merging them with their
* fallback locales. If an entry is read for a locale alias (e.g. "mo")
* that points to a locale with a fallback locale ("ro_MD"), the reader
* can continue at the correct fallback locale ("ro").
*
* @param array $localeAliases A mapping of locale aliases to locales
*/
public function setLocaleAliases(array $localeAliases): void
{
$this->localeAliases = $localeAliases;
}
public function read(string $path, string $locale): mixed
{
return $this->reader->read($path, $locale);
}
public function readEntry(string $path, string $locale, array $indices, bool $fallback = true): mixed
{
$entry = null;
$isMultiValued = false;
$readSucceeded = false;
$exception = null;
$currentLocale = $locale;
$testedLocales = [];
while (null !== $currentLocale) {
// Resolve any aliases to their target locales
if (isset($this->localeAliases[$currentLocale])) {
$currentLocale = $this->localeAliases[$currentLocale];
}
try {
$data = $this->reader->read($path, $currentLocale);
$currentEntry = RecursiveArrayAccess::get($data, $indices);
$readSucceeded = true;
$isCurrentTraversable = $currentEntry instanceof \Traversable;
$isCurrentMultiValued = $isCurrentTraversable || \is_array($currentEntry);
// Return immediately if fallback is disabled or we are dealing
// with a scalar non-null entry
if (!$fallback || (!$isCurrentMultiValued && null !== $currentEntry)) {
return $currentEntry;
}
// =========================================================
// Fallback is enabled, entry is either multi-valued or NULL
// =========================================================
// If entry is multi-valued, convert to array
if ($isCurrentTraversable) {
$currentEntry = iterator_to_array($currentEntry);
}
// If previously read entry was multi-valued too, merge them
if ($isCurrentMultiValued && $isMultiValued) {
$currentEntry = array_merge($currentEntry, $entry);
}
// Keep the previous entry if the current entry is NULL
if (null !== $currentEntry) {
$entry = $currentEntry;
}
// If this or the previous entry was multi-valued, we are dealing
// with a merged, multi-valued entry now
$isMultiValued = $isMultiValued || $isCurrentMultiValued;
} catch (ResourceBundleNotFoundException $e) {
// Continue if there is a fallback locale for the current
// locale
$exception = $e;
} catch (OutOfBoundsException $e) {
// Remember exception and rethrow if we cannot find anything in
// the fallback locales either
$exception = $e;
}
// Remember which locales we tried
$testedLocales[] = $currentLocale;
// Check whether fallback is allowed
if (!$fallback) {
break;
}
// Then determine fallback locale
$currentLocale = Locale::getFallback($currentLocale);
}
// Multi-valued entry was merged
if ($isMultiValued) {
return $entry;
}
// Entry is still NULL, but no read error occurred
if ($readSucceeded) {
return $entry;
}
// Entry is still NULL, read error occurred. Throw an exception
// containing the detailed path and locale
$errorMessage = sprintf(
'Couldn\'t read the indices [%s] for the locale "%s" in "%s".',
implode('][', $indices),
$locale,
$path
);
// Append fallback locales, if any
if (\count($testedLocales) > 1) {
// Remove original locale
array_shift($testedLocales);
$errorMessage .= sprintf(
' The indices also couldn\'t be found for the fallback locale(s) "%s".',
implode('", "', $testedLocales)
);
}
throw new MissingResourceException($errorMessage, 0, $exception);
}
}

View File

@@ -0,0 +1,54 @@
<?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\Bundle\Reader;
use Symfony\Component\Intl\Exception\MissingResourceException;
/**
* Reads individual entries of a resource file.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
interface BundleEntryReaderInterface extends BundleReaderInterface
{
/**
* Reads an entry from a resource bundle.
*
* An entry can be selected from the resource bundle by passing the path
* to that entry in the bundle. For example, if the bundle is structured
* like this:
*
* TopLevel
* NestedLevel
* Entry: Value
*
* Then the value can be read by calling:
*
* $reader->readEntry('...', 'en', ['TopLevel', 'NestedLevel', 'Entry']);
*
* @param string $path The path to the resource bundle
* @param string[] $indices The indices to read from the bundle
* @param bool $fallback Whether to merge the value with the value from
* the fallback locale (e.g. "en" for "en_GB").
* Only applicable if the result is multivalued
* (i.e. array or \ArrayAccess) or cannot be found
* in the requested locale.
*
* @return mixed returns an array or {@link \ArrayAccess} instance for
* complex data and a scalar value for simple data
*
* @throws MissingResourceException If the indices cannot be accessed
*/
public function readEntry(string $path, string $locale, array $indices, bool $fallback = true): mixed;
}

View File

@@ -0,0 +1,28 @@
<?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\Bundle\Reader;
/**
* Reads resource bundle files.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
interface BundleReaderInterface
{
/**
* @return mixed returns an array or {@link \ArrayAccess} instance for
* complex data, a scalar value otherwise
*/
public function read(string $path, string $locale): mixed;
}

View File

@@ -0,0 +1,47 @@
<?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\Bundle\Reader;
use Symfony\Component\Intl\Data\Util\ArrayAccessibleResourceBundle;
use Symfony\Component\Intl\Exception\ResourceBundleNotFoundException;
/**
* Reads binary .res resource bundles.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
class IntlBundleReader implements BundleReaderInterface
{
public function read(string $path, string $locale): mixed
{
// Point for future extension: Modify this class so that it works also
// if the \ResourceBundle class is not available.
try {
// Never enable fallback. We want to know if a bundle cannot be found
$bundle = new \ResourceBundle($locale, $path, false);
} catch (\Exception) {
$bundle = null;
}
// The bundle is NULL if the path does not look like a resource bundle
// (i.e. contain a bunch of *.res files)
if (null === $bundle) {
throw new ResourceBundleNotFoundException(sprintf('The resource bundle "%s/%s.res" could not be found.', $path, $locale));
}
// Other possible errors are U_USING_FALLBACK_WARNING and U_ZERO_ERROR,
// which are OK for us.
return new ArrayAccessibleResourceBundle($bundle);
}
}

View File

@@ -0,0 +1,47 @@
<?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\Bundle\Reader;
use Symfony\Component\Intl\Exception\ResourceBundleNotFoundException;
use Symfony\Component\Intl\Exception\RuntimeException;
/**
* Reads .json resource bundles.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
class JsonBundleReader implements BundleReaderInterface
{
public function read(string $path, string $locale): mixed
{
$fileName = $path.'/'.$locale.'.json';
// prevent directory traversal attacks
if (\dirname($fileName) !== $path) {
throw new ResourceBundleNotFoundException(sprintf('The resource bundle "%s" does not exist.', $fileName));
}
if (!is_file($fileName)) {
throw new ResourceBundleNotFoundException(sprintf('The resource bundle "%s" does not exist.', $fileName));
}
$data = json_decode(file_get_contents($fileName), true);
if (null === $data) {
throw new RuntimeException(sprintf('The resource bundle "%s" contains invalid JSON: ', $fileName).json_last_error_msg());
}
return $data;
}
}

View File

@@ -0,0 +1,45 @@
<?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\Bundle\Reader;
use Symfony\Component\Intl\Exception\ResourceBundleNotFoundException;
use Symfony\Component\Intl\Util\GzipStreamWrapper;
/**
* Reads .php resource bundles.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
class PhpBundleReader implements BundleReaderInterface
{
public function read(string $path, string $locale): mixed
{
$fileName = $path.'/'.$locale.'.php';
// prevent directory traversal attacks
if (\dirname($fileName) !== $path) {
throw new ResourceBundleNotFoundException(sprintf('The resource bundle "%s" does not exist.', $fileName));
}
if (is_file($fileName.'.gz')) {
return GzipStreamWrapper::require($fileName.'.gz');
}
if (!is_file($fileName)) {
throw new ResourceBundleNotFoundException(sprintf('The resource bundle "%s" does not exist.', $fileName));
}
return include $fileName;
}
}

View File

@@ -0,0 +1,27 @@
<?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\Bundle\Writer;
/**
* Writes resource bundle files.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
interface BundleWriterInterface
{
/**
* @return void
*/
public function write(string $path, string $locale, mixed $data);
}

View File

@@ -0,0 +1,39 @@
<?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\Bundle\Writer;
/**
* Writes .json resource bundles.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
class JsonBundleWriter implements BundleWriterInterface
{
public function write(string $path, string $locale, mixed $data): void
{
if ($data instanceof \Traversable) {
$data = iterator_to_array($data);
}
array_walk_recursive($data, function (&$value) {
if ($value instanceof \Traversable) {
$value = iterator_to_array($value);
}
});
$contents = json_encode($data, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_UNICODE)."\n";
file_put_contents($path.'/'.$locale.'.json', $contents);
}
}

View File

@@ -0,0 +1,46 @@
<?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\Bundle\Writer;
use Symfony\Component\VarExporter\VarExporter;
/**
* Writes .php resource bundles.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
class PhpBundleWriter implements BundleWriterInterface
{
public function write(string $path, string $locale, mixed $data): void
{
$template = <<<'TEMPLATE'
<?php
return %s;
TEMPLATE;
if ($data instanceof \Traversable) {
$data = iterator_to_array($data);
}
array_walk_recursive($data, function (&$value) {
if ($value instanceof \Traversable) {
$value = iterator_to_array($value);
}
});
file_put_contents($path.'/'.$locale.'.php', sprintf($template, VarExporter::export($data)));
}
}

View File

@@ -0,0 +1,205 @@
<?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\Bundle\Writer;
/**
* Writes .txt resource bundles.
*
* The resulting files can be converted to binary .res files using a
* {@link \Symfony\Component\Intl\ResourceBundle\Compiler\BundleCompilerInterface}
* implementation.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
*
* @internal
*/
class TextBundleWriter implements BundleWriterInterface
{
public function write(string $path, string $locale, mixed $data, bool $fallback = true): void
{
$file = fopen($path.'/'.$locale.'.txt', 'w');
$this->writeResourceBundle($file, $locale, $data, $fallback);
fclose($file);
}
/**
* Writes a "resourceBundle" node.
*
* @param resource $file The file handle to write to
* @param mixed $value The value of the node
*
* @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
*/
private function writeResourceBundle($file, string $bundleName, mixed $value, bool $fallback): void
{
fwrite($file, $bundleName);
$this->writeTable($file, $value, 0, $fallback);
fwrite($file, "\n");
}
/**
* Writes a "resource" node.
*
* @param resource $file The file handle to write to
* @param mixed $value The value of the node
*
* @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
*/
private function writeResource($file, mixed $value, int $indentation, bool $requireBraces = true): void
{
if (\is_int($value)) {
$this->writeInteger($file, $value);
return;
}
if ($value instanceof \Traversable) {
$value = iterator_to_array($value);
}
if (\is_array($value)) {
$intValues = \count($value) === \count(array_filter($value, 'is_int'));
// check that the keys are 0-indexed and ascending
$intKeys = array_is_list($value);
if ($intValues && $intKeys) {
$this->writeIntVector($file, $value, $indentation);
return;
}
if ($intKeys) {
$this->writeArray($file, $value, $indentation);
return;
}
$this->writeTable($file, $value, $indentation);
return;
}
if (\is_bool($value)) {
$value = $value ? 'true' : 'false';
}
$this->writeString($file, (string) $value, $requireBraces);
}
/**
* Writes an "integer" node.
*
* @param resource $file The file handle to write to
*
* @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
*/
private function writeInteger($file, int $value): void
{
fprintf($file, ':int{%d}', $value);
}
/**
* Writes an "intvector" node.
*
* @param resource $file The file handle to write to
*
* @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
*/
private function writeIntVector($file, array $value, int $indentation): void
{
fwrite($file, ":intvector{\n");
foreach ($value as $int) {
fprintf($file, "%s%d,\n", str_repeat(' ', $indentation + 1), $int);
}
fprintf($file, '%s}', str_repeat(' ', $indentation));
}
/**
* Writes a "string" node.
*
* @param resource $file The file handle to write to
*
* @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
*/
private function writeString($file, string $value, bool $requireBraces = true): void
{
if ($requireBraces) {
fprintf($file, '{"%s"}', $value);
return;
}
fprintf($file, '"%s"', $value);
}
/**
* Writes an "array" node.
*
* @param resource $file The file handle to write to
*
* @see http://source.icu-project.org/repos/icu/icuhtml/trunk/design/bnf_rb.txt
*/
private function writeArray($file, array $value, int $indentation): void
{
fwrite($file, "{\n");
foreach ($value as $entry) {
fwrite($file, str_repeat(' ', $indentation + 1));
$this->writeResource($file, $entry, $indentation + 1, false);
fwrite($file, ",\n");
}
fprintf($file, '%s}', str_repeat(' ', $indentation));
}
/**
* Writes a "table" node.
*
* @param resource $file The file handle to write to
*/
private function writeTable($file, iterable $value, int $indentation, bool $fallback = true): void
{
if (!$fallback) {
fwrite($file, ':table(nofallback)');
}
fwrite($file, "{\n");
foreach ($value as $key => $entry) {
fwrite($file, str_repeat(' ', $indentation + 1));
// escape colons, otherwise they are interpreted as resource types
if (str_contains($key, ':') || str_contains($key, ' ')) {
$key = '"'.$key.'"';
}
fwrite($file, $key);
$this->writeResource($file, $entry, $indentation + 1);
fwrite($file, "\n");
}
fprintf($file, '%s}', str_repeat(' ', $indentation));
}
}

View File

@@ -0,0 +1,107 @@
<?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\Generator;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Intl\Data\Bundle\Compiler\BundleCompilerInterface;
use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReader;
use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface;
use Symfony\Component\Intl\Data\Bundle\Reader\IntlBundleReader;
use Symfony\Component\Intl\Data\Util\LocaleScanner;
/**
* The rule for compiling the currency bundle.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
abstract class AbstractDataGenerator
{
private BundleCompilerInterface $compiler;
private string $dirName;
public function __construct(BundleCompilerInterface $compiler, string $dirName)
{
$this->compiler = $compiler;
$this->dirName = $dirName;
}
public function generateData(GeneratorConfig $config): void
{
$filesystem = new Filesystem();
$localeScanner = new LocaleScanner();
$reader = new BundleEntryReader(new IntlBundleReader());
$writers = $config->getBundleWriters();
$tempDir = sys_get_temp_dir().'/icu-data-'.$this->dirName;
// Prepare filesystem directories
foreach ($writers as $targetDir => $writer) {
$filesystem->remove($targetDir.'/'.$this->dirName);
$filesystem->mkdir($targetDir.'/'.$this->dirName);
}
$filesystem->remove($tempDir);
$filesystem->mkdir($tempDir);
$locales = $this->scanLocales($localeScanner, $config->getSourceDir());
$this->compileTemporaryBundles($this->compiler, $config->getSourceDir(), $tempDir);
$this->preGenerate();
foreach ($locales as $locale) {
$localeData = $this->generateDataForLocale($reader, $tempDir, $locale);
if (null !== $localeData) {
foreach ($writers as $targetDir => $writer) {
$writer->write($targetDir.'/'.$this->dirName, $locale, $localeData);
}
}
}
$rootData = $this->generateDataForRoot($reader, $tempDir);
if (null !== $rootData) {
foreach ($writers as $targetDir => $writer) {
$writer->write($targetDir.'/'.$this->dirName, 'root', $rootData);
}
}
$metaData = $this->generateDataForMeta($reader, $tempDir);
if (null !== $metaData) {
foreach ($writers as $targetDir => $writer) {
$writer->write($targetDir.'/'.$this->dirName, 'meta', $metaData);
}
}
// Clean up
$filesystem->remove($tempDir);
}
/**
* @return string[]
*/
abstract protected function scanLocales(LocaleScanner $scanner, string $sourceDir): array;
abstract protected function compileTemporaryBundles(BundleCompilerInterface $compiler, string $sourceDir, string $tempDir): void;
abstract protected function preGenerate(): void;
abstract protected function generateDataForLocale(BundleEntryReaderInterface $reader, string $tempDir, string $displayLocale): ?array;
abstract protected function generateDataForRoot(BundleEntryReaderInterface $reader, string $tempDir): ?array;
abstract protected function generateDataForMeta(BundleEntryReaderInterface $reader, string $tempDir): ?array;
}

View File

@@ -0,0 +1,159 @@
<?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\Generator;
use Symfony\Component\Intl\Data\Bundle\Compiler\BundleCompilerInterface;
use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface;
use Symfony\Component\Intl\Data\Util\ArrayAccessibleResourceBundle;
use Symfony\Component\Intl\Data\Util\LocaleScanner;
/**
* The rule for compiling the currency bundle.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
class CurrencyDataGenerator extends AbstractDataGenerator
{
private const DENYLIST = [
'XBA' => true, // European Composite Unit
'XBB' => true, // European Monetary Unit
'XBC' => true, // European Unit of Account (XBC)
'XBD' => true, // European Unit of Account (XBD)
'XUA' => true, // ADB Unit of Account
'XAU' => true, // Gold
'XAG' => true, // Silver
'XPT' => true, // Platinum
'XPD' => true, // Palladium
'XSU' => true, // Sucre
'XDR' => true, // Special Drawing Rights
'XTS' => true, // Testing Currency Code
'XXX' => true, // Unknown Currency
];
/**
* Collects all available currency codes.
*
* @var string[]
*/
private array $currencyCodes = [];
protected function scanLocales(LocaleScanner $scanner, string $sourceDir): array
{
return $scanner->scanLocales($sourceDir.'/curr');
}
protected function compileTemporaryBundles(BundleCompilerInterface $compiler, string $sourceDir, string $tempDir): void
{
$compiler->compile($sourceDir.'/curr', $tempDir);
$compiler->compile($sourceDir.'/misc/currencyNumericCodes.txt', $tempDir);
}
protected function preGenerate(): void
{
$this->currencyCodes = [];
}
protected function generateDataForLocale(BundleEntryReaderInterface $reader, string $tempDir, string $displayLocale): ?array
{
$localeBundle = $reader->read($tempDir, $displayLocale);
if (isset($localeBundle['Currencies']) && null !== $localeBundle['Currencies']) {
$data = [
'Names' => $this->generateSymbolNamePairs($localeBundle),
];
$this->currencyCodes = array_merge($this->currencyCodes, array_keys($data['Names']));
return $data;
}
return null;
}
protected function generateDataForRoot(BundleEntryReaderInterface $reader, string $tempDir): ?array
{
$rootBundle = $reader->read($tempDir, 'root');
return [
'Names' => $this->generateSymbolNamePairs($rootBundle),
];
}
protected function generateDataForMeta(BundleEntryReaderInterface $reader, string $tempDir): ?array
{
$supplementalDataBundle = $reader->read($tempDir, 'supplementalData');
$numericCodesBundle = $reader->read($tempDir, 'currencyNumericCodes');
$this->currencyCodes = array_unique($this->currencyCodes);
sort($this->currencyCodes);
$data = [
'Currencies' => $this->currencyCodes,
'Meta' => $this->generateCurrencyMeta($supplementalDataBundle),
'Alpha3ToNumeric' => $this->generateAlpha3ToNumericMapping($numericCodesBundle, $this->currencyCodes),
];
$data['NumericToAlpha3'] = $this->generateNumericToAlpha3Mapping($data['Alpha3ToNumeric']);
return $data;
}
private function generateSymbolNamePairs(ArrayAccessibleResourceBundle $rootBundle): array
{
$symbolNamePairs = array_map(fn ($pair) => \array_slice(iterator_to_array($pair), 0, 2), iterator_to_array($rootBundle['Currencies']));
// Remove unwanted currencies
$symbolNamePairs = array_diff_key($symbolNamePairs, self::DENYLIST);
return $symbolNamePairs;
}
private function generateCurrencyMeta(ArrayAccessibleResourceBundle $supplementalDataBundle): array
{
// The metadata is already de-duplicated. It contains one key "DEFAULT"
// which is used for currencies that don't have dedicated entries.
return iterator_to_array($supplementalDataBundle['CurrencyMeta']);
}
private function generateAlpha3ToNumericMapping(ArrayAccessibleResourceBundle $numericCodesBundle, array $currencyCodes): array
{
$alpha3ToNumericMapping = iterator_to_array($numericCodesBundle['codeMap']);
asort($alpha3ToNumericMapping);
// Filter unknown currencies (e.g. "AYM")
$alpha3ToNumericMapping = array_intersect_key($alpha3ToNumericMapping, array_flip($currencyCodes));
return $alpha3ToNumericMapping;
}
private function generateNumericToAlpha3Mapping(array $alpha3ToNumericMapping): array
{
$numericToAlpha3Mapping = [];
foreach ($alpha3ToNumericMapping as $alpha3 => $numeric) {
// Make sure that the mapping is stored as table and not as array
$numeric = (string) $numeric;
if (!isset($numericToAlpha3Mapping[$numeric])) {
$numericToAlpha3Mapping[$numeric] = [];
}
$numericToAlpha3Mapping[$numeric][] = $alpha3;
}
return $numericToAlpha3Mapping;
}
}

View File

@@ -0,0 +1,58 @@
<?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\Generator;
use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface;
use Symfony\Component\Intl\Locale;
/**
* @author Roland Franssen <franssen.roland@gmail.com>
*
* @internal
*/
trait FallbackTrait
{
private array $fallbackCache = [];
private bool $generatingFallback = false;
/**
* @see AbstractDataGenerator::generateDataForLocale()
*/
abstract protected function generateDataForLocale(BundleEntryReaderInterface $reader, string $tempDir, string $displayLocale): ?array;
/**
* @see AbstractDataGenerator::generateDataForRoot()
*/
abstract protected function generateDataForRoot(BundleEntryReaderInterface $reader, string $tempDir): ?array;
private function generateFallbackData(BundleEntryReaderInterface $reader, string $tempDir, string $displayLocale): array
{
if (null === $fallback = Locale::getFallback($displayLocale)) {
return [];
}
if (isset($this->fallbackCache[$fallback])) {
return $this->fallbackCache[$fallback];
}
$prevGeneratingFallback = $this->generatingFallback;
$this->generatingFallback = true;
try {
$data = 'root' === $fallback ? $this->generateDataForRoot($reader, $tempDir) : $this->generateDataForLocale($reader, $tempDir, $fallback);
} finally {
$this->generatingFallback = $prevGeneratingFallback;
}
return $this->fallbackCache[$fallback] = $data ?: [];
}
}

View File

@@ -0,0 +1,73 @@
<?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\Generator;
use Symfony\Component\Intl\Data\Bundle\Writer\BundleWriterInterface;
/**
* Stores contextual information for resource bundle generation.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
class GeneratorConfig
{
private string $sourceDir;
private string $icuVersion;
/**
* @var BundleWriterInterface[]
*/
private array $bundleWriters = [];
public function __construct(string $sourceDir, string $icuVersion)
{
$this->sourceDir = $sourceDir;
$this->icuVersion = $icuVersion;
}
/**
* Adds a writer to be used during the data conversion.
*/
public function addBundleWriter(string $targetDir, BundleWriterInterface $writer): void
{
$this->bundleWriters[$targetDir] = $writer;
}
/**
* Returns the writers indexed by their output directories.
*
* @return BundleWriterInterface[]
*/
public function getBundleWriters(): array
{
return $this->bundleWriters;
}
/**
* Returns the directory where the source versions of the resource bundles
* are stored.
*/
public function getSourceDir(): string
{
return $this->sourceDir;
}
/**
* Returns the ICU version of the bundles being converted.
*/
public function getIcuVersion(): string
{
return $this->icuVersion;
}
}

View File

@@ -0,0 +1,234 @@
<?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\Generator;
use Symfony\Component\Intl\Data\Bundle\Compiler\BundleCompilerInterface;
use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface;
use Symfony\Component\Intl\Data\Util\ArrayAccessibleResourceBundle;
use Symfony\Component\Intl\Data\Util\LocaleScanner;
use Symfony\Component\Intl\Exception\RuntimeException;
/**
* The rule for compiling the language bundle.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
class LanguageDataGenerator extends AbstractDataGenerator
{
/**
* Source: https://iso639-3.sil.org/code_tables/639/data.
*/
private const PREFERRED_ALPHA2_TO_ALPHA3_MAPPING = [
'ak' => 'aka',
'ar' => 'ara',
'ay' => 'aym',
'az' => 'aze',
'bo' => 'bod',
'cr' => 'cre',
'cs' => 'ces',
'cy' => 'cym',
'de' => 'deu',
'dz' => 'dzo',
'el' => 'ell',
'et' => 'est',
'eu' => 'eus',
'fa' => 'fas',
'ff' => 'ful',
'fr' => 'fra',
'gn' => 'grn',
'hy' => 'hye',
'hr' => 'hrv',
'ik' => 'ipk',
'is' => 'isl',
'iu' => 'iku',
'ka' => 'kat',
'kr' => 'kau',
'kg' => 'kon',
'kv' => 'kom',
'ku' => 'kur',
'lv' => 'lav',
'mg' => 'mlg',
'mi' => 'mri',
'mk' => 'mkd',
'mn' => 'mon',
'ms' => 'msa',
'my' => 'mya',
'nb' => 'nob',
'ne' => 'nep',
'nl' => 'nld',
'oj' => 'oji',
'om' => 'orm',
'or' => 'ori',
'ps' => 'pus',
'qu' => 'que',
'ro' => 'ron',
'sc' => 'srd',
'sk' => 'slk',
'sq' => 'sqi',
'sr' => 'srp',
'sw' => 'swa',
'uz' => 'uzb',
'yi' => 'yid',
'za' => 'zha',
'zh' => 'zho',
];
private const DENYLIST = [
'root' => true, // Absolute root language
'mul' => true, // Multiple languages
'mis' => true, // Uncoded language
'und' => true, // Unknown language
'zxx' => true, // No linguistic content
];
/**
* Collects all available language codes.
*
* @var string[]
*/
private array $languageCodes = [];
protected function scanLocales(LocaleScanner $scanner, string $sourceDir): array
{
return $scanner->scanLocales($sourceDir.'/lang');
}
protected function compileTemporaryBundles(BundleCompilerInterface $compiler, string $sourceDir, string $tempDir): void
{
$compiler->compile($sourceDir.'/lang', $tempDir);
$compiler->compile($sourceDir.'/misc/metadata.txt', $tempDir);
}
protected function preGenerate(): void
{
$this->languageCodes = [];
}
protected function generateDataForLocale(BundleEntryReaderInterface $reader, string $tempDir, string $displayLocale): ?array
{
$localeBundle = $reader->read($tempDir, $displayLocale);
// isset() on \ResourceBundle returns true even if the value is null
if (isset($localeBundle['Languages']) && null !== $localeBundle['Languages']) {
$names = [];
$localizedNames = [];
foreach (self::generateLanguageNames($localeBundle) as $language => $name) {
if (!str_contains($language, '_')) {
$this->languageCodes[] = $language;
$names[$language] = $name;
} else {
$localizedNames[$language] = $name;
}
}
return [
'Names' => $names,
'LocalizedNames' => $localizedNames,
];
}
return null;
}
protected function generateDataForRoot(BundleEntryReaderInterface $reader, string $tempDir): ?array
{
return null;
}
protected function generateDataForMeta(BundleEntryReaderInterface $reader, string $tempDir): ?array
{
$metadataBundle = $reader->read($tempDir, 'metadata');
$this->languageCodes = array_unique($this->languageCodes);
sort($this->languageCodes);
return [
'Languages' => $this->languageCodes,
'Alpha3Languages' => $this->generateAlpha3Codes($this->languageCodes, $metadataBundle),
'Alpha2ToAlpha3' => $this->generateAlpha2ToAlpha3Mapping($metadataBundle),
'Alpha3ToAlpha2' => $this->generateAlpha3ToAlpha2Mapping($metadataBundle),
];
}
private static function generateLanguageNames(ArrayAccessibleResourceBundle $localeBundle): array
{
return array_diff_key(iterator_to_array($localeBundle['Languages']), self::DENYLIST);
}
private function generateAlpha3Codes(array $languageCodes, ArrayAccessibleResourceBundle $metadataBundle): array
{
$alpha3Codes = array_flip(array_filter($languageCodes, static fn (string $language): bool => 3 === \strlen($language)));
foreach ($metadataBundle['alias']['language'] as $alias => $data) {
if (3 === \strlen($alias) && 'overlong' === $data['reason']) {
$alpha3Codes[$alias] = true;
}
}
ksort($alpha3Codes);
return array_keys($alpha3Codes);
}
private function generateAlpha2ToAlpha3Mapping(ArrayAccessibleResourceBundle $metadataBundle): array
{
$aliases = iterator_to_array($metadataBundle['alias']['language']);
$alpha2ToAlpha3 = [];
foreach ($aliases as $alias => $data) {
$language = $data['replacement'];
if (2 === \strlen($language) && 3 === \strlen($alias) && 'overlong' === $data['reason']) {
if (isset(self::PREFERRED_ALPHA2_TO_ALPHA3_MAPPING[$language])) {
// Validate to prevent typos
if (!isset($aliases[self::PREFERRED_ALPHA2_TO_ALPHA3_MAPPING[$language]])) {
throw new RuntimeException('The statically set three-letter mapping '.self::PREFERRED_ALPHA2_TO_ALPHA3_MAPPING[$language].' for the language code '.$language.' seems to be invalid. Typo?');
}
$alpha3 = self::PREFERRED_ALPHA2_TO_ALPHA3_MAPPING[$language];
$alpha2 = $aliases[$alpha3]['replacement'];
if ($language !== $alpha2) {
throw new RuntimeException('The statically set three-letter mapping '.$alpha3.' for the language code '.$language.' seems to be an alias for '.$alpha2.'. Wrong mapping?');
}
$alpha2ToAlpha3[$language] = $alpha3;
} elseif (isset($alpha2ToAlpha3[$language])) {
throw new RuntimeException('Multiple three-letter mappings exist for the language code '.$language.'. Please add one of them to the const PREFERRED_ALPHA2_TO_ALPHA3_MAPPING.');
} else {
$alpha2ToAlpha3[$language] = $alias;
}
}
}
asort($alpha2ToAlpha3);
return $alpha2ToAlpha3;
}
private function generateAlpha3ToAlpha2Mapping(ArrayAccessibleResourceBundle $metadataBundle): array
{
$alpha3ToAlpha2 = [];
foreach ($metadataBundle['alias']['language'] as $alias => $data) {
$language = $data['replacement'];
if (2 === \strlen($language) && 3 === \strlen($alias) && \in_array($data['reason'], ['overlong', 'bibliographic'], true)) {
$alpha3ToAlpha2[$alias] = $language;
}
}
asort($alpha3ToAlpha2);
return $alpha3ToAlpha2;
}
}

View File

@@ -0,0 +1,167 @@
<?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\Generator;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Intl\Data\Bundle\Compiler\BundleCompilerInterface;
use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface;
use Symfony\Component\Intl\Data\Util\LocaleScanner;
use Symfony\Component\Intl\Exception\MissingResourceException;
/**
* The rule for compiling the locale bundle.
*
* @author Bernhard Schussek <bschussek@gmail.com>
* @author Roland Franssen <franssen.roland@gmail.com>
*
* @internal
*/
class LocaleDataGenerator extends AbstractDataGenerator
{
use FallbackTrait;
private array $locales = [];
private array $localeAliases = [];
private array $localeParents = [];
protected function scanLocales(LocaleScanner $scanner, string $sourceDir): array
{
$this->locales = $scanner->scanLocales($sourceDir.'/locales');
$this->localeAliases = $scanner->scanAliases($sourceDir.'/locales');
$this->localeParents = $scanner->scanParents($sourceDir.'/locales');
return $this->locales;
}
protected function compileTemporaryBundles(BundleCompilerInterface $compiler, string $sourceDir, string $tempDir): void
{
$filesystem = new Filesystem();
$filesystem->mkdir([
$tempDir.'/lang',
$tempDir.'/region',
]);
$compiler->compile($sourceDir.'/lang', $tempDir.'/lang');
$compiler->compile($sourceDir.'/region', $tempDir.'/region');
}
protected function preGenerate(): void
{
// Write parents locale file for the Translation component
file_put_contents(
__DIR__.'/../../../Translation/Resources/data/parents.json',
json_encode($this->localeParents, \JSON_PRETTY_PRINT).\PHP_EOL
);
}
protected function generateDataForLocale(BundleEntryReaderInterface $reader, string $tempDir, string $displayLocale): ?array
{
// Don't generate aliases, as they are resolved during runtime
// Unless an alias is needed as fallback for de-duplication purposes
if (isset($this->localeAliases[$displayLocale]) && !$this->generatingFallback) {
return null;
}
// Generate locale names for all locales that have translations in
// at least the language or the region bundle
$displayFormat = $reader->readEntry($tempDir.'/lang', $displayLocale, ['localeDisplayPattern']);
$pattern = $displayFormat['pattern'] ?? '{0} ({1})';
$separator = $displayFormat['separator'] ?? '{0}, {1}';
$localeNames = [];
foreach ($this->locales as $locale) {
// Ensure a normalized list of pure locales
if (\Locale::getAllVariants($locale)) {
continue;
}
try {
// Generate a locale name in the language of each display locale
// Each locale name has the form: "Language (Script, Region, Variant1, ...)
// Script, Region and Variants are optional. If none of them is
// available, the braces are not printed.
$localeNames[$locale] = $this->generateLocaleName($reader, $tempDir, $locale, $displayLocale, $pattern, $separator);
} catch (MissingResourceException) {
// Silently ignore incomplete locale names
// In this case one should configure at least one fallback locale that is complete (e.g. English) during
// runtime. Alternatively a translation for the missing resource can be proposed upstream.
}
}
$data = [
'Names' => $localeNames,
];
// Don't de-duplicate a fallback locale
// Ensures the display locale can be de-duplicated on itself
if ($this->generatingFallback) {
return $data;
}
// Process again to de-duplicate locale and its fallback locales
// Only keep the differences
$fallbackData = $this->generateFallbackData($reader, $tempDir, $displayLocale);
if (isset($fallbackData['Names'])) {
$data['Names'] = array_diff($data['Names'], $fallbackData['Names']);
}
if (!$data['Names']) {
return null;
}
return $data;
}
protected function generateDataForRoot(BundleEntryReaderInterface $reader, string $tempDir): ?array
{
return null;
}
protected function generateDataForMeta(BundleEntryReaderInterface $reader, string $tempDir): ?array
{
return [
'Locales' => $this->locales,
'Aliases' => $this->localeAliases,
];
}
private function generateLocaleName(BundleEntryReaderInterface $reader, string $tempDir, string $locale, string $displayLocale, string $pattern, string $separator): string
{
// Apply generic notation using square brackets as described per http://cldr.unicode.org/translation/language-names
$name = str_replace(['(', ')'], ['[', ']'], $reader->readEntry($tempDir.'/lang', $displayLocale, ['Languages', \Locale::getPrimaryLanguage($locale)]));
$extras = [];
// Discover the name of the script part of the locale
// i.e. in zh_Hans_MO, "Hans" is the script
if ($script = \Locale::getScript($locale)) {
$extras[] = str_replace(['(', ')'], ['[', ']'], $reader->readEntry($tempDir.'/lang', $displayLocale, ['Scripts', $script]));
}
// Discover the name of the region part of the locale
// i.e. in de_AT, "AT" is the region
if ($region = \Locale::getRegion($locale)) {
if (ctype_alpha($region) && !RegionDataGenerator::isValidCountryCode($region)) {
throw new MissingResourceException(sprintf('Skipping "%s" due an invalid country.', $locale));
}
$extras[] = str_replace(['(', ')'], ['[', ']'], $reader->readEntry($tempDir.'/region', $displayLocale, ['Countries', $region]));
}
if ($extras) {
$extra = array_shift($extras);
foreach ($extras as $part) {
$extra = str_replace(['{0}', '{1}'], [$extra, $part], $separator);
}
$name = str_replace(['{0}', '{1}'], [$name, $extra], $pattern);
}
return $name;
}
}

View File

@@ -0,0 +1,264 @@
<?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\Generator;
use Symfony\Component\Intl\Data\Bundle\Compiler\BundleCompilerInterface;
use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface;
use Symfony\Component\Intl\Data\Util\ArrayAccessibleResourceBundle;
use Symfony\Component\Intl\Data\Util\LocaleScanner;
use Symfony\Component\Intl\Exception\RuntimeException;
/**
* The rule for compiling the region bundle.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @see http://source.icu-project.org/repos/icu/icu4j/trunk/main/classes/core/src/com/ibm/icu/util/Region.java
*
* @internal
*/
class RegionDataGenerator extends AbstractDataGenerator
{
/**
* Source: https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes.
*/
private const PREFERRED_ALPHA2_TO_ALPHA3_MAPPING = [
'CD' => 'COD',
'DE' => 'DEU',
'FR' => 'FRA',
'MM' => 'MMR',
'TL' => 'TLS',
'YE' => 'YEM',
];
private const DENYLIST = [
// Exceptional reservations
'AC' => true, // Ascension Island
'CP' => true, // Clipperton Island
'CQ' => true, // Island of Sark
'DG' => true, // Diego Garcia
'EA' => true, // Ceuta & Melilla
'EU' => true, // European Union
'EZ' => true, // Eurozone
'IC' => true, // Canary Islands
'TA' => true, // Tristan da Cunha
'UN' => true, // United Nations
// User-assigned
'QO' => true, // Outlying Oceania
'XA' => true, // Pseudo-Accents
'XB' => true, // Pseudo-Bidi
'XK' => true, // Kosovo
// Misc
'ZZ' => true, // Unknown Region
];
// @see https://en.wikipedia.org/wiki/ISO_3166-1_numeric#Withdrawn_codes
private const WITHDRAWN_CODES = [
128, // Canton and Enderbury Islands
200, // Czechoslovakia
216, // Dronning Maud Land
230, // Ethiopia
249, // France, Metropolitan
278, // German Democratic Republic
280, // Germany, Federal Republic of
396, // Johnston Island
488, // Midway Islands
530, // Netherlands Antilles
532, // Netherlands Antilles
536, // Neutral Zone
582, // Pacific Islands (Trust Territory)
590, // Panama
658, // Saint Kitts-Nevis-Anguilla
720, // Yemen, Democratic
736, // Sudan
810, // USSR
849, // United States Miscellaneous Pacific Islands
872, // Wake Island
886, // Yemen Arab Republic
890, // Yugoslavia, Socialist Federal Republic of
891, // Serbia and Montenegro
];
/**
* Collects all available language codes.
*
* @var string[]
*/
private array $regionCodes = [];
public static function isValidCountryCode(int|string|null $region): bool
{
if (isset(self::DENYLIST[$region])) {
return false;
}
// WORLD/CONTINENT/SUBCONTINENT/GROUPING
if (\is_int($region) || ctype_digit($region)) {
return false;
}
return true;
}
protected function scanLocales(LocaleScanner $scanner, string $sourceDir): array
{
return $scanner->scanLocales($sourceDir.'/region');
}
protected function compileTemporaryBundles(BundleCompilerInterface $compiler, string $sourceDir, string $tempDir): void
{
$compiler->compile($sourceDir.'/region', $tempDir);
$compiler->compile($sourceDir.'/misc/metadata.txt', $tempDir);
}
protected function preGenerate(): void
{
$this->regionCodes = [];
}
protected function generateDataForLocale(BundleEntryReaderInterface $reader, string $tempDir, string $displayLocale): ?array
{
$localeBundle = $reader->read($tempDir, $displayLocale);
// isset() on \ResourceBundle returns true even if the value is null
if (isset($localeBundle['Countries']) && null !== $localeBundle['Countries']) {
$data = [
'Names' => $this->generateRegionNames($localeBundle),
];
$this->regionCodes = array_merge($this->regionCodes, array_keys($data['Names']));
return $data;
}
return null;
}
protected function generateDataForRoot(BundleEntryReaderInterface $reader, string $tempDir): ?array
{
return null;
}
protected function generateDataForMeta(BundleEntryReaderInterface $reader, string $tempDir): ?array
{
$metadataBundle = $reader->read($tempDir, 'metadata');
$this->regionCodes = array_unique($this->regionCodes);
sort($this->regionCodes);
$alpha2ToAlpha3 = $this->generateAlpha2ToAlpha3Mapping(array_flip($this->regionCodes), $metadataBundle);
$alpha3ToAlpha2 = array_flip($alpha2ToAlpha3);
asort($alpha3ToAlpha2);
$alpha2ToNumeric = $this->generateAlpha2ToNumericMapping($metadataBundle);
$numericToAlpha2 = [];
foreach ($alpha2ToNumeric as $alpha2 => $numeric) {
// Add underscore prefix to force keys with leading zeros to remain as string keys.
$numericToAlpha2['_'.$numeric] = $alpha2;
}
asort($numericToAlpha2);
return [
'Regions' => $this->regionCodes,
'Alpha2ToAlpha3' => $alpha2ToAlpha3,
'Alpha3ToAlpha2' => $alpha3ToAlpha2,
'Alpha2ToNumeric' => $alpha2ToNumeric,
'NumericToAlpha2' => $numericToAlpha2,
];
}
protected function generateRegionNames(ArrayAccessibleResourceBundle $localeBundle): array
{
$unfilteredRegionNames = iterator_to_array($localeBundle['Countries']);
$regionNames = [];
foreach ($unfilteredRegionNames as $region => $regionName) {
if (!self::isValidCountryCode($region)) {
continue;
}
$regionNames[$region] = $regionName;
}
return $regionNames;
}
private function generateAlpha2ToAlpha3Mapping(array $countries, ArrayAccessibleResourceBundle $metadataBundle): array
{
$aliases = iterator_to_array($metadataBundle['alias']['territory']);
$alpha2ToAlpha3 = [];
foreach ($aliases as $alias => $data) {
$country = $data['replacement'];
if (2 === \strlen($country) && 3 === \strlen($alias) && 'overlong' === $data['reason']) {
if (isset(self::PREFERRED_ALPHA2_TO_ALPHA3_MAPPING[$country])) {
// Validate to prevent typos
if (!isset($aliases[self::PREFERRED_ALPHA2_TO_ALPHA3_MAPPING[$country]])) {
throw new RuntimeException('The statically set three-letter mapping '.self::PREFERRED_ALPHA2_TO_ALPHA3_MAPPING[$country].' for the country code '.$country.' seems to be invalid. Typo?');
}
$alpha3 = self::PREFERRED_ALPHA2_TO_ALPHA3_MAPPING[$country];
$alpha2 = $aliases[$alpha3]['replacement'];
if ($country !== $alpha2) {
throw new RuntimeException('The statically set three-letter mapping '.$alpha3.' for the country code '.$country.' seems to be an alias for '.$alpha2.'. Wrong mapping?');
}
$alpha2ToAlpha3[$country] = $alpha3;
} elseif (isset($alpha2ToAlpha3[$country])) {
throw new RuntimeException('Multiple three-letter mappings exist for the country code '.$country.'. Please add one of them to the const PREFERRED_ALPHA2_TO_ALPHA3_MAPPING.');
} elseif (isset($countries[$country]) && self::isValidCountryCode($alias)) {
$alpha2ToAlpha3[$country] = $alias;
}
}
}
asort($alpha2ToAlpha3);
return $alpha2ToAlpha3;
}
private function generateAlpha2ToNumericMapping(ArrayAccessibleResourceBundle $metadataBundle): array
{
$aliases = iterator_to_array($metadataBundle['alias']['territory']);
$alpha2ToNumeric = [];
foreach ($aliases as $alias => $data) {
if (!is_numeric($alias)) {
continue;
}
if (\in_array($alias, self::WITHDRAWN_CODES)) {
continue;
}
if (isset(self::DENYLIST[$data['replacement']])) {
continue;
}
if ('deprecated' === $data['reason']) {
continue;
}
$alpha2ToNumeric[$data['replacement']] = (string) $alias;
}
ksort($alpha2ToNumeric);
return $alpha2ToNumeric;
}
}

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\Intl\Data\Generator;
use Symfony\Component\Intl\Data\Bundle\Compiler\BundleCompilerInterface;
use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface;
use Symfony\Component\Intl\Data\Util\LocaleScanner;
/**
* The rule for compiling the script bundle.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
class ScriptDataGenerator extends AbstractDataGenerator
{
private const DENYLIST = [
'Zzzz' => true, // Unknown Script
];
/**
* Collects all available language codes.
*
* @var string[]
*/
private array $scriptCodes = [];
protected function scanLocales(LocaleScanner $scanner, string $sourceDir): array
{
return $scanner->scanLocales($sourceDir.'/lang');
}
protected function compileTemporaryBundles(BundleCompilerInterface $compiler, string $sourceDir, string $tempDir): void
{
$compiler->compile($sourceDir.'/lang', $tempDir);
}
protected function preGenerate(): void
{
$this->scriptCodes = [];
}
protected function generateDataForLocale(BundleEntryReaderInterface $reader, string $tempDir, string $displayLocale): ?array
{
$localeBundle = $reader->read($tempDir, $displayLocale);
// isset() on \ResourceBundle returns true even if the value is null
if (isset($localeBundle['Scripts']) && null !== $localeBundle['Scripts']) {
$data = [
'Names' => array_diff_key(iterator_to_array($localeBundle['Scripts']), self::DENYLIST),
];
$this->scriptCodes = array_merge($this->scriptCodes, array_keys($data['Names']));
return $data;
}
return null;
}
protected function generateDataForRoot(BundleEntryReaderInterface $reader, string $tempDir): ?array
{
return null;
}
protected function generateDataForMeta(BundleEntryReaderInterface $reader, string $tempDir): ?array
{
$this->scriptCodes = array_unique($this->scriptCodes);
sort($this->scriptCodes);
return [
'Scripts' => $this->scriptCodes,
];
}
}

View File

@@ -0,0 +1,274 @@
<?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\Generator;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Intl\Data\Bundle\Compiler\BundleCompilerInterface;
use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface;
use Symfony\Component\Intl\Data\Util\ArrayAccessibleResourceBundle;
use Symfony\Component\Intl\Data\Util\LocaleScanner;
use Symfony\Component\Intl\Exception\MissingResourceException;
use Symfony\Component\Intl\Locale;
/**
* The rule for compiling the zone bundle.
*
* @author Roland Franssen <franssen.roland@gmail.com>
*
* @internal
*/
class TimezoneDataGenerator extends AbstractDataGenerator
{
use FallbackTrait;
/**
* Collects all available zone IDs.
*
* @var string[]
*/
private array $zoneIds = [];
private array $zoneToCountryMapping = [];
private array $localeAliases = [];
protected function scanLocales(LocaleScanner $scanner, string $sourceDir): array
{
$this->localeAliases = $scanner->scanAliases($sourceDir.'/locales');
return $scanner->scanLocales($sourceDir.'/zone');
}
protected function compileTemporaryBundles(BundleCompilerInterface $compiler, string $sourceDir, string $tempDir): void
{
$filesystem = new Filesystem();
$filesystem->mkdir($tempDir.'/region');
$compiler->compile($sourceDir.'/region', $tempDir.'/region');
$compiler->compile($sourceDir.'/zone', $tempDir);
$compiler->compile($sourceDir.'/misc/timezoneTypes.txt', $tempDir);
$compiler->compile($sourceDir.'/misc/metaZones.txt', $tempDir);
$compiler->compile($sourceDir.'/misc/windowsZones.txt', $tempDir);
}
protected function preGenerate(): void
{
$this->zoneIds = [];
$this->zoneToCountryMapping = [];
}
protected function generateDataForLocale(BundleEntryReaderInterface $reader, string $tempDir, string $displayLocale): ?array
{
if (!$this->zoneToCountryMapping) {
$this->zoneToCountryMapping = self::generateZoneToCountryMapping($reader->read($tempDir, 'windowsZones'));
}
// Don't generate aliases, as they are resolved during runtime
// Unless an alias is needed as fallback for de-duplication purposes
if (isset($this->localeAliases[$displayLocale]) && !$this->generatingFallback) {
return null;
}
$localeBundle = $reader->read($tempDir, $displayLocale);
if (!isset($localeBundle['zoneStrings']) || null === $localeBundle['zoneStrings']) {
return null;
}
$data = [
'Names' => $this->generateZones($reader, $tempDir, $displayLocale),
'Meta' => self::generateZoneMetadata($localeBundle),
];
// Don't de-duplicate a fallback locale
// Ensures the display locale can be de-duplicated on itself
if ($this->generatingFallback) {
return $data;
}
// Process again to de-duplicate locales and their fallback locales
// Only keep the differences
$fallback = $this->generateFallbackData($reader, $tempDir, $displayLocale);
if (isset($fallback['Names'])) {
$data['Names'] = array_diff($data['Names'], $fallback['Names']);
}
if (isset($fallback['Meta'])) {
$data['Meta'] = array_diff($data['Meta'], $fallback['Meta']);
}
if (!$data['Names'] && !$data['Meta']) {
return null;
}
$this->zoneIds = array_merge($this->zoneIds, array_keys($data['Names']));
return $data;
}
protected function generateDataForRoot(BundleEntryReaderInterface $reader, string $tempDir): ?array
{
$rootBundle = $reader->read($tempDir, 'root');
return [
'Meta' => self::generateZoneMetadata($rootBundle),
];
}
protected function generateDataForMeta(BundleEntryReaderInterface $reader, string $tempDir): ?array
{
$rootBundle = $reader->read($tempDir, 'root');
$this->zoneIds = array_unique($this->zoneIds);
sort($this->zoneIds);
ksort($this->zoneToCountryMapping);
$data = [
'Zones' => $this->zoneIds,
'ZoneToCountry' => $this->zoneToCountryMapping,
'CountryToZone' => self::generateCountryToZoneMapping($this->zoneToCountryMapping),
];
return $data;
}
private function generateZones(BundleEntryReaderInterface $reader, string $tempDir, string $locale): array
{
$typeBundle = $reader->read($tempDir, 'timezoneTypes');
$available = [];
foreach ($typeBundle['typeMap']['timezone'] as $zone => $_) {
if ('Etc:Unknown' === $zone || preg_match('~^Etc:GMT[-+]\d+$~', $zone)) {
continue;
}
$available[$zone] = true;
}
$metaBundle = $reader->read($tempDir, 'metaZones');
$metazones = [];
foreach ($metaBundle['metazoneInfo'] as $zone => $info) {
foreach ($info as $metazone) {
$metazones[$zone] = $metazone->get(0);
}
}
$regionFormat = $reader->readEntry($tempDir, $locale, ['zoneStrings', 'regionFormat']);
$fallbackFormat = $reader->readEntry($tempDir, $locale, ['zoneStrings', 'fallbackFormat']);
$resolveName = function (string $id, ?string $city = null) use ($reader, $tempDir, $locale, $regionFormat, $fallbackFormat): ?string {
// Resolve default name as described per http://cldr.unicode.org/translation/timezones
if (isset($this->zoneToCountryMapping[$id])) {
try {
$country = $reader->readEntry($tempDir.'/region', $locale, ['Countries', $this->zoneToCountryMapping[$id]]);
} catch (MissingResourceException) {
return null;
}
$name = str_replace('{0}', $country, $regionFormat);
return null === $city ? $name : str_replace(['{0}', '{1}'], [$city, $name], $fallbackFormat);
}
if (null !== $city) {
return str_replace('{0}', $city, $regionFormat);
}
return null;
};
$accessor = static function (array $indices, array ...$fallbackIndices) use ($locale, $reader, $tempDir) {
foreach (\func_get_args() as $indices) {
try {
return $reader->readEntry($tempDir, $locale, $indices);
} catch (MissingResourceException) {
}
}
return null;
};
$zones = [];
foreach (array_keys($available) as $zone) {
// lg: long generic, e.g. "Central European Time"
// ls: long specific (not DST), e.g. "Central European Standard Time"
// ld: long DST, e.g. "Central European Summer Time"
// ec: example city, e.g. "Amsterdam"
$name = $accessor(['zoneStrings', $zone, 'lg'], ['zoneStrings', $zone, 'ls']);
$city = $accessor(['zoneStrings', $zone, 'ec']);
$id = str_replace(':', '/', $zone);
if (null === $name && isset($metazones[$zone])) {
$meta = 'meta:'.$metazones[$zone];
$name = $accessor(['zoneStrings', $meta, 'lg'], ['zoneStrings', $meta, 'ls']);
}
// Infer a default English named city for all locales
// Ensures each timezone ID has a distinctive name
if (null === $city && 0 !== strrpos($zone, 'Etc:') && false !== $i = strrpos($zone, ':')) {
$city = str_replace('_', ' ', substr($zone, $i + 1));
}
if (null === $name) {
$name = $resolveName($id, $city);
$city = null;
}
if (null === $name) {
continue;
}
// Ensure no duplicated content is generated
if (null !== $city && false === mb_stripos(str_replace('-', ' ', $name), str_replace('-', ' ', $city))) {
$name = str_replace(['{0}', '{1}'], [$city, $name], $fallbackFormat);
}
$zones[$id] = $name;
}
return $zones;
}
private static function generateZoneMetadata(ArrayAccessibleResourceBundle $localeBundle): array
{
$metadata = [];
if (isset($localeBundle['zoneStrings']['gmtFormat'])) {
$metadata['GmtFormat'] = str_replace('{0}', '%s', $localeBundle['zoneStrings']['gmtFormat']);
}
if (isset($localeBundle['zoneStrings']['hourFormat'])) {
$hourFormat = explode(';', str_replace(['HH', 'mm', 'H', 'm'], ['%02d', '%02d', '%d', '%d'], $localeBundle['zoneStrings']['hourFormat']), 2);
$metadata['HourFormatPos'] = $hourFormat[0];
$metadata['HourFormatNeg'] = $hourFormat[1];
}
return $metadata;
}
private static function generateZoneToCountryMapping(ArrayAccessibleResourceBundle $windowsZoneBundle): array
{
$mapping = [];
foreach ($windowsZoneBundle['mapTimezones'] as $zoneInfo) {
foreach ($zoneInfo as $region => $zones) {
if (RegionDataGenerator::isValidCountryCode($region)) {
$mapping += array_fill_keys(explode(' ', $zones), $region);
}
}
}
ksort($mapping);
return $mapping;
}
private static function generateCountryToZoneMapping(array $zoneToCountryMapping): array
{
$mapping = [];
foreach ($zoneToCountryMapping as $zone => $country) {
$mapping[$country][] = $zone;
}
ksort($mapping);
return $mapping;
}
}

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]);
}
}
}

View File

@@ -0,0 +1,21 @@
<?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\Exception;
/**
* Base BadMethodCallException for the Intl component.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface
{
}

View File

@@ -0,0 +1,21 @@
<?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\Exception;
/**
* Base ExceptionInterface for the Intl component.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface ExceptionInterface extends \Throwable
{
}

View File

@@ -0,0 +1,21 @@
<?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\Exception;
/**
* InvalidArgumentException for the Intl component.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}

View File

@@ -0,0 +1,21 @@
<?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\Exception;
/**
* Thrown when an invalid entry of a resource bundle was requested.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class MissingResourceException extends RuntimeException
{
}

View File

@@ -0,0 +1,21 @@
<?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\Exception;
/**
* Base OutOfBoundsException for the Intl component.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
{
}

View File

@@ -0,0 +1,19 @@
<?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\Exception;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class ResourceBundleNotFoundException extends RuntimeException
{
}

View File

@@ -0,0 +1,21 @@
<?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\Exception;
/**
* RuntimeException for the Intl component.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}

View File

@@ -0,0 +1,25 @@
<?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\Exception;
/**
* Thrown when a method argument had an unexpected type.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class UnexpectedTypeException extends InvalidArgumentException
{
public function __construct(mixed $value, string $expectedType)
{
parent::__construct(sprintf('Expected argument of type "%s", "%s" given', $expectedType, get_debug_type($value)));
}
}

View File

@@ -0,0 +1,126 @@
<?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;
/**
* Gives access to internationalization data.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
final class Intl
{
/**
* The number of resource bundles to buffer. Loading the same resource
* bundle for n locales takes up n spots in the buffer.
*/
public const BUFFER_SIZE = 10;
/**
* The directory name of the currency data.
*/
public const CURRENCY_DIR = 'currencies';
/**
* The directory name of the language data.
*/
public const LANGUAGE_DIR = 'languages';
/**
* The directory name of the script data.
*/
public const SCRIPT_DIR = 'scripts';
/**
* The directory name of the locale data.
*/
public const LOCALE_DIR = 'locales';
/**
* The directory name of the region data.
*/
public const REGION_DIR = 'regions';
/**
* The directory name of the zone data.
*/
public const TIMEZONE_DIR = 'timezones';
private static string|false|null $icuVersion = false;
private static string $icuDataVersion;
/**
* Returns whether the intl extension is installed.
*/
public static function isExtensionLoaded(): bool
{
return class_exists(\ResourceBundle::class);
}
/**
* Returns the version of the installed ICU library.
*/
public static function getIcuVersion(): ?string
{
if (false === self::$icuVersion) {
if (!self::isExtensionLoaded()) {
self::$icuVersion = self::getIcuStubVersion();
} elseif (\defined('INTL_ICU_VERSION')) {
self::$icuVersion = \INTL_ICU_VERSION;
} else {
try {
$reflector = new \ReflectionExtension('intl');
ob_start();
$reflector->info();
$output = strip_tags(ob_get_clean());
preg_match('/^ICU version (?:=>)?(.*)$/m', $output, $matches);
self::$icuVersion = trim($matches[1]);
} catch (\ReflectionException) {
self::$icuVersion = null;
}
}
}
return self::$icuVersion;
}
/**
* Returns the version of the installed ICU data.
*/
public static function getIcuDataVersion(): string
{
return self::$icuDataVersion ??= trim(file_get_contents(self::getDataDirectory().'/version.txt'));
}
/**
* Returns the ICU version that the stub classes mimic.
*/
public static function getIcuStubVersion(): string
{
return '76.1';
}
/**
* Returns the absolute path to the data directory.
*/
public static function getDataDirectory(): string
{
return __DIR__.'/Resources/data';
}
/**
* This class must not be instantiated.
*/
private function __construct()
{
}
}

View File

@@ -0,0 +1,19 @@
Copyright (c) 2004-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,182 @@
<?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;
use Symfony\Component\Intl\Exception\MissingResourceException;
/**
* Gives access to language-related ICU data.
*
* @author Bernhard Schussek <bschussek@gmail.com>
* @author Roland Franssen <franssen.roland@gmail.com>
*/
final class Languages extends ResourceBundle
{
/**
* Returns all available languages as two-letter codes.
*
* Languages are returned as lowercase ISO 639-1 two-letter language codes.
* For languages that don't have a two-letter code, the ISO 639-2
* three-letter code is used instead.
*
* A full table of ISO 639 language codes can be found here:
* http://www-01.sil.org/iso639-3/codes.asp
*
* @return string[] an array of canonical ISO 639-1 language codes
*/
public static function getLanguageCodes(): array
{
return self::readEntry(['Languages'], 'meta');
}
public static function exists(string $language): bool
{
try {
self::readEntry(['Names', $language]);
return true;
} catch (MissingResourceException) {
return false;
}
}
/**
* Gets the language name from its alpha2 code.
*
* A full locale may be passed to obtain a more localized language name, e.g. "American English" for "en_US".
*
* @throws MissingResourceException if the language code does not exist
*/
public static function getName(string $language, ?string $displayLocale = null): string
{
try {
return self::readEntry(['Names', $language], $displayLocale);
} catch (MissingResourceException) {
try {
return self::readEntry(['LocalizedNames', $language], $displayLocale);
} catch (MissingResourceException $e) {
if (false !== $i = strrpos($language, '_')) {
return self::getName(substr($language, 0, $i), $displayLocale);
}
throw $e;
}
}
}
/**
* Gets the list of language names indexed with alpha2 codes as keys.
*
* @return array<string, string>
*/
public static function getNames(?string $displayLocale = null): array
{
return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale);
}
/**
* Returns the ISO 639-2 three-letter code of a language, given a two-letter code.
*
* @throws MissingResourceException if the language has no corresponding three-letter code
*/
public static function getAlpha3Code(string $language): string
{
return self::readEntry(['Alpha2ToAlpha3', $language], 'meta');
}
/**
* Returns the ISO 639-1 two-letter code of a language, given a three letter code.
*
* @throws MissingResourceException if the language has no corresponding three-letter code
*/
public static function getAlpha2Code(string $language): string
{
return self::readEntry(['Alpha3ToAlpha2', $language], 'meta');
}
/**
* Returns all available languages as three-letter codes.
*
* Languages are returned as lowercase ISO 639-2 three-letter language codes.
*
* @return string[] an array of canonical ISO 639-2 language codes
*/
public static function getAlpha3Codes(): array
{
return self::readEntry(['Alpha3Languages'], 'meta');
}
/**
* @param string $language ISO 639-2 three-letter language code
*/
public static function alpha3CodeExists(string $language): bool
{
try {
self::getAlpha2Code($language);
return true;
} catch (MissingResourceException) {
static $cache;
$cache ??= array_flip(self::getAlpha3Codes());
return isset($cache[$language]);
}
}
/**
* Gets the language name from its ISO 639-2 three-letter code.
*
* @throws MissingResourceException if the country code does not exists
*/
public static function getAlpha3Name(string $language, ?string $displayLocale = null): string
{
try {
return self::getName(self::getAlpha2Code($language), $displayLocale);
} catch (MissingResourceException $e) {
if (3 === \strlen($language)) {
return self::getName($language, $displayLocale);
}
throw $e;
}
}
/**
* Gets the list of language names indexed with ISO 639-2 three-letter codes as keys.
*
* Same as method getNames, but with ISO 639-2 three-letter codes instead of ISO 639-1 codes as keys.
*
* @return array<string, string>
*/
public static function getAlpha3Names(?string $displayLocale = null): array
{
$alpha2Names = self::getNames($displayLocale);
$alpha3Names = [];
foreach ($alpha2Names as $alpha2Code => $name) {
if (3 === \strlen($alpha2Code)) {
$alpha3Names[$alpha2Code] = $name;
continue;
}
try {
$alpha3Names[self::getAlpha3Code($alpha2Code)] = $name;
} catch (MissingResourceException) {
}
}
return $alpha3Names;
}
protected static function getPath(): string
{
return Intl::getDataDirectory().'/'.Intl::LANGUAGE_DIR;
}
}

View File

@@ -0,0 +1,112 @@
<?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;
if (!class_exists(\Locale::class)) {
throw new \LogicException(sprintf('You cannot use the "%s\Locale" class as the "intl" extension is not installed. See https://php.net/intl.', __NAMESPACE__));
}
/**
* Provides access to locale-related data.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @internal
*/
final class Locale extends \Locale
{
private static ?string $defaultFallback = 'en';
/**
* Sets the default fallback locale.
*
* The default fallback locale is used as fallback for locales that have no
* fallback otherwise.
*
* @see getFallback()
*/
public static function setDefaultFallback(?string $locale): void
{
self::$defaultFallback = $locale;
}
/**
* Returns the default fallback locale.
*
* @see setDefaultFallback()
* @see getFallback()
*/
public static function getDefaultFallback(): ?string
{
return self::$defaultFallback;
}
/**
* Returns the fallback locale for a given locale.
*
* For example, the fallback of "fr_FR" is "fr". The fallback of "fr" is
* the default fallback locale configured with {@link setDefaultFallback()}.
* The default fallback locale has no fallback.
*
* @return string|null The ICU locale code of the fallback locale, or null
* if no fallback exists
*/
public static function getFallback(string $locale): ?string
{
if (\function_exists('locale_parse')) {
$localeSubTags = locale_parse($locale) ?? ['language' => $locale];
if (1 === \count($localeSubTags)) {
if ('root' !== self::$defaultFallback && self::$defaultFallback === $localeSubTags['language']) {
return 'root';
}
// Don't return default fallback for "root", "meta" or others
// Normal locales have two or three letters
if (\strlen($locale) < 4) {
return self::$defaultFallback;
}
return null;
}
array_pop($localeSubTags);
$fallback = locale_compose($localeSubTags);
return false !== $fallback ? $fallback : null;
}
if (false !== $pos = strrpos($locale, '_')) {
return substr($locale, 0, $pos);
}
if (false !== $pos = strrpos($locale, '-')) {
return substr($locale, 0, $pos);
}
if ('root' !== self::$defaultFallback && self::$defaultFallback === $locale) {
return 'root';
}
// Don't return default fallback for "root", "meta" or others
// Normal locales have two or three letters
return \strlen($locale) < 4 ? self::$defaultFallback : null;
}
/**
* This class must not be instantiated.
*/
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;
use Symfony\Component\Intl\Exception\MissingResourceException;
/**
* Gives access to locale-related ICU data.
*
* @author Bernhard Schussek <bschussek@gmail.com>
* @author Roland Franssen <franssen.roland@gmail.com>
*/
final class Locales extends ResourceBundle
{
/**
* @return string[]
*/
public static function getLocales(): array
{
return self::readEntry(['Locales'], 'meta');
}
/**
* @return string[]
*/
public static function getAliases(): array
{
return self::readEntry(['Aliases'], 'meta');
}
public static function exists(string $locale): bool
{
try {
self::readEntry(['Names', $locale]);
return true;
} catch (MissingResourceException) {
return \in_array($locale, self::getAliases(), true);
}
}
/**
* @throws MissingResourceException if the locale does not exist
*/
public static function getName(string $locale, ?string $displayLocale = null): string
{
try {
return self::readEntry(['Names', $locale], $displayLocale);
} catch (MissingResourceException $e) {
if (false === $aliased = array_search($locale, self::getAliases(), true)) {
throw $e;
}
return self::readEntry(['Names', $aliased], $displayLocale);
}
}
/**
* @return string[]
*/
public static function getNames(?string $displayLocale = null): array
{
return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale);
}
protected static function getPath(): string
{
return Intl::getDataDirectory().'/'.Intl::LOCALE_DIR;
}
}

View File

@@ -0,0 +1,13 @@
Intl Component
=============
The Intl component provides access to the localization data of the ICU library.
Resources
---------
* [Documentation](https://symfony.com/doc/current/components/intl.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)

View File

@@ -0,0 +1,76 @@
<?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;
use Symfony\Component\Intl\Data\Bundle\Reader\BufferedBundleReader;
use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReader;
use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface;
use Symfony\Component\Intl\Data\Bundle\Reader\PhpBundleReader;
/**
* @author Roland Franssen <franssen.roland@gmail.com>
*
* @internal
*/
abstract class ResourceBundle
{
private static BundleEntryReader $entryReader;
abstract protected static function getPath(): string;
/**
* Reads an entry from a resource bundle.
*
* @see BundleEntryReaderInterface::readEntry()
*
* @param string[] $indices The indices to read from the bundle
* @param string|null $locale The locale to read
* @param bool $fallback Whether to merge the value with the value from
* the fallback locale (e.g. "en" for "en_GB").
* Only applicable if the result is multivalued
* (i.e. array or \ArrayAccess) or cannot be found
* in the requested locale.
*
* @return mixed returns an array or {@link \ArrayAccess} instance for
* complex data and a scalar value for simple data
*/
final protected static function readEntry(array $indices, ?string $locale = null, bool $fallback = true): mixed
{
if (!isset(self::$entryReader)) {
self::$entryReader = new BundleEntryReader(new BufferedBundleReader(
new PhpBundleReader(),
Intl::BUFFER_SIZE
));
$localeAliases = self::$entryReader->readEntry(Intl::getDataDirectory().'/'.Intl::LOCALE_DIR, 'meta', ['Aliases']);
self::$entryReader->setLocaleAliases($localeAliases instanceof \Traversable ? iterator_to_array($localeAliases) : $localeAliases);
}
return self::$entryReader->readEntry(static::getPath(), $locale ?? \Locale::getDefault(), $indices, $fallback);
}
final protected static function asort(iterable $list, ?string $locale = null): array
{
if ($list instanceof \Traversable) {
$list = iterator_to_array($list);
}
$collator = new \Collator($locale ?? \Locale::getDefault());
$collator->asort($list);
return $list;
}
private function __construct()
{
}
}

View File

@@ -0,0 +1,18 @@
<?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.
*/
$autoload = __DIR__.'/../../vendor/autoload.php';
if (!file_exists($autoload)) {
bailout('You should run "composer install" in the component before running this script.');
}
require_once $autoload;

View File

@@ -0,0 +1,109 @@
<?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.
*/
if ('cli' !== \PHP_SAPI) {
throw new Exception('This script must be run from the command line.');
}
define('LINE_WIDTH', 75);
define('LINE', str_repeat('-', LINE_WIDTH)."\n");
function bailout(string $message)
{
echo wordwrap($message, LINE_WIDTH)." Aborting.\n";
exit(1);
}
/**
* @return string
*/
function strip_minor_versions(string $version)
{
preg_match('/^(?P<version>[0-9]\.[0-9]|[0-9]{2,})/', $version, $matches);
return $matches['version'];
}
/**
* @return string
*/
function centered(string $text)
{
$padding = (int) ((LINE_WIDTH - strlen($text)) / 2);
return str_repeat(' ', $padding).$text;
}
function cd(string $dir): void
{
if (false === chdir($dir)) {
bailout("Could not switch to directory $dir.");
}
}
function run(string $command): void
{
exec($command, $output, $status);
if (0 !== $status) {
$output = implode("\n", $output);
echo "Error while running:\n ".getcwd().'$ '.$command."\nOutput:\n".LINE."$output\n".LINE;
bailout("\"$command\" failed.");
}
}
/**
* @return string|null
*/
function get_icu_version_from_genrb(string $genrb)
{
exec($genrb.' --version - 2>&1', $output, $status);
if (0 !== $status) {
bailout($genrb.' failed.');
}
if (!preg_match('/ICU version ([\d\.]+)/', implode('', $output), $matches)) {
return null;
}
return $matches[1];
}
error_reporting(\E_ALL);
set_error_handler(function (int $type, string $msg, string $file, int $line) {
throw new \ErrorException($msg, 0, $type, $file, $line);
});
set_exception_handler(function (Throwable $exception) {
echo "\n";
$cause = $exception;
$root = true;
while (null !== $cause) {
if (!$root) {
echo "Caused by\n";
}
echo $cause::class.': '.$cause->getMessage()."\n";
echo "\n";
echo $cause->getFile().':'.$cause->getLine()."\n";
echo $cause->getTraceAsString()."\n";
$cause = $cause->getPrevious();
$root = false;
}
});

View File

@@ -0,0 +1,12 @@
#!/usr/bin/env bash
[[ ! -d /tmp/symfony/icu ]] && mkdir -p /tmp/symfony/icu
docker run \
-it --rm --name symfony-intl \
-u $(id -u):$(id -g) \
-v /tmp/symfony/icu:/tmp \
-v $(pwd):/symfony \
-w /symfony \
jakzal/php-intl:8.3-74.1 \
php src/Symfony/Component/Intl/Resources/bin/update-data.php

View File

@@ -0,0 +1,36 @@
#!/usr/bin/env php
<?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.
*/
if ('cli' !== PHP_SAPI) {
throw new Exception('This script must be run from the command line.');
}
if (!extension_loaded('zlib')) {
throw new Exception('This script requires the zlib extension.');
}
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
dirname(__DIR__).'/data',
FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS
)
);
foreach ($iterator as $file) {
if ('php' !== $file->getExtension() || 'meta.php' === $file->getFilename()) {
continue;
}
$data = file_get_contents($file);
file_put_contents('compress.zlib://'.$file.'.gz', $data);
unlink($file.(filesize($file.'.gz') >= strlen($data) ? '.gz' : ''));
}

View File

@@ -0,0 +1,238 @@
<?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.
*/
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Intl\Data\Bundle\Compiler\GenrbCompiler;
use Symfony\Component\Intl\Data\Bundle\Writer\PhpBundleWriter;
use Symfony\Component\Intl\Data\Generator\CurrencyDataGenerator;
use Symfony\Component\Intl\Data\Generator\GeneratorConfig;
use Symfony\Component\Intl\Data\Generator\LanguageDataGenerator;
use Symfony\Component\Intl\Data\Generator\LocaleDataGenerator;
use Symfony\Component\Intl\Data\Generator\RegionDataGenerator;
use Symfony\Component\Intl\Data\Generator\ScriptDataGenerator;
use Symfony\Component\Intl\Data\Generator\TimezoneDataGenerator;
use Symfony\Component\Intl\Intl;
use Symfony\Component\Intl\Locale;
use Symfony\Component\Intl\Util\GitRepository;
if ('cli' !== \PHP_SAPI) {
throw new Exception('This script must be run from the command line.');
}
require_once __DIR__.'/common.php';
require_once __DIR__.'/autoload.php';
$argc = $_SERVER['argc'];
$argv = $_SERVER['argv'];
if ($argc > 3 || 2 === $argc && '-h' === $argv[1]) {
bailout(<<<'MESSAGE'
Usage: php update-data.php <path/to/icu/source> <path/to/icu/build>
Updates the ICU data for Symfony to the latest version of ICU.
If you downloaded the git repository before, you can pass the path to the
repository source in the first optional argument.
If you also built the repository before, you can pass the directory where that
build is stored in the second parameter. The build directory needs to contain
the subdirectories bin/ and lib/.
For running this script, the intl extension must be loaded and all vendors
must have been installed through composer:
composer install
MESSAGE
);
}
echo LINE;
echo centered('ICU Resource Bundle Compilation')."\n";
echo LINE;
if (!Intl::isExtensionLoaded()) {
bailout('The intl extension for PHP is not installed.');
}
if ($argc >= 2) {
$repoDir = $argv[1];
$git = new GitRepository($repoDir);
echo "Using the existing git repository at {$repoDir}.\n";
} else {
echo "Starting git clone. This may take a while...\n";
$repoDir = sys_get_temp_dir().'/icu-data';
$git = GitRepository::download('https://github.com/unicode-org/icu.git', $repoDir);
echo "Git clone to {$repoDir} complete.\n";
}
$gitTag = $git->getLastTag(fn ($tag) => preg_match('#^release-[0-9]{1,}-[0-9]{1}$#', $tag));
$shortIcuVersion = strip_minor_versions(preg_replace('#release-([0-9]{1,})-([0-9]{1,})#', '$1.$2', $gitTag));
echo "Checking out `{$gitTag}` for version `{$shortIcuVersion}`...\n";
$git->checkout('tags/'.$gitTag);
$filesystem = new Filesystem();
$sourceDir = $repoDir.'/icu4c/source';
if ($argc >= 3) {
$buildDir = $argv[2];
} else {
// Always build genrb so that we can determine the ICU version of the
// download by running genrb --version
echo "Building genrb.\n";
cd($sourceDir);
echo "Running configure...\n";
$buildDir = sys_get_temp_dir().'/icu-data/'.$shortIcuVersion.'/build';
$filesystem->remove($buildDir);
$filesystem->mkdir($buildDir);
run('./configure --prefix='.$buildDir.' 2>&1');
echo "Running make...\n";
// If the directory "lib" does not exist in the download, create it or we
// will run into problems when building libicuuc.so.
$filesystem->mkdir($sourceDir.'/lib');
// If the directory "bin" does not exist in the download, create it or we
// will run into problems when building genrb.
$filesystem->mkdir($sourceDir.'/bin');
echo '[1/6] libicudata.so...';
cd($sourceDir.'/stubdata');
run('make 2>&1 && make install 2>&1');
echo " ok.\n";
echo '[2/6] libicuuc.so...';
cd($sourceDir.'/common');
run('make 2>&1 && make install 2>&1');
echo " ok.\n";
echo '[3/6] libicui18n.so...';
cd($sourceDir.'/i18n');
run('make 2>&1 && make install 2>&1');
echo " ok.\n";
echo '[4/6] libicutu.so...';
cd($sourceDir.'/tools/toolutil');
run('make 2>&1 && make install 2>&1');
echo " ok.\n";
echo '[5/6] libicuio.so...';
cd($sourceDir.'/io');
run('make 2>&1 && make install 2>&1');
echo " ok.\n";
echo '[6/6] genrb...';
cd($sourceDir.'/tools/genrb');
run('make 2>&1 && make install 2>&1');
echo " ok.\n";
}
$genrb = $buildDir.'/bin/genrb';
if (\PHP_OS === 'Darwin') {
$genrbEnv = 'DYLD_LIBRARY_PATH='.$buildDir.'/lib ';
} else {
$genrbEnv = 'LD_LIBRARY_PATH='.$buildDir.'/lib ';
}
echo "Using $genrb.\n";
$icuVersionInDownload = get_icu_version_from_genrb($genrbEnv.' '.$genrb);
echo "Preparing resource bundle compilation (version $icuVersionInDownload)...\n";
$compiler = new GenrbCompiler($genrb, $genrbEnv);
$config = new GeneratorConfig($sourceDir.'/data', $icuVersionInDownload);
$dataDir = dirname(__DIR__).'/data';
$config->addBundleWriter($dataDir, new PhpBundleWriter());
echo "Starting resource bundle compilation. This may take a while...\n";
// We don't want to use fallback to English during generation
Locale::setDefaultFallback('root');
echo "Generating language data...\n";
$generator = new LanguageDataGenerator($compiler, Intl::LANGUAGE_DIR);
$generator->generateData($config);
echo "Generating script data...\n";
$generator = new ScriptDataGenerator($compiler, Intl::SCRIPT_DIR);
$generator->generateData($config);
echo "Generating region data...\n";
$generator = new RegionDataGenerator($compiler, Intl::REGION_DIR);
$generator->generateData($config);
echo "Generating currency data...\n";
$generator = new CurrencyDataGenerator($compiler, Intl::CURRENCY_DIR);
$generator->generateData($config);
echo "Generating locale data...\n";
$generator = new LocaleDataGenerator($compiler, Intl::LOCALE_DIR);
$generator->generateData($config);
echo "Generating timezone data...\n";
$generator = new TimezoneDataGenerator($compiler, Intl::TIMEZONE_DIR);
$generator->generateData($config);
echo "Resource bundle compilation complete.\n";
$gitInfo = <<<GIT_INFO
Git information
===============
URL: {$git->getUrl()}
Revision: {$git->getLastCommitHash()}
Author: {$git->getLastAuthor()}
Date: {$git->getLastAuthoredDate()->format('c')}
GIT_INFO;
$gitInfoFile = $dataDir.'/git-info.txt';
file_put_contents($gitInfoFile, $gitInfo);
echo "Wrote $gitInfoFile.\n";
$versionFile = $dataDir.'/version.txt';
file_put_contents($versionFile, "$icuVersionInDownload\n");
echo "Wrote $versionFile.\n";
echo "Done.\n";

View File

@@ -0,0 +1,690 @@
<?php
return [
'Names' => [
'AED' => [
'AED',
'Verenigde Arabiese Emirate-dirham',
],
'AFN' => [
'AFN',
'Afgaanse afgani',
],
'ALL' => [
'ALL',
'Albanese lek',
],
'AMD' => [
'AMD',
'Armeense dram',
],
'ANG' => [
'ANG',
'Nederlands-Antilliaanse gulde',
],
'AOA' => [
'AOA',
'Angolese kwanza',
],
'ARS' => [
'ARS',
'Argentynse peso',
],
'AUD' => [
'A$',
'Australiese dollar',
],
'AWG' => [
'AWG',
'Arubaanse floryn',
],
'AZN' => [
'AZN',
'Azerbeidjaanse manat',
],
'BAM' => [
'BAM',
'Bosnies-Herzegowiniese omskakelbare marka',
],
'BBD' => [
'BBD',
'Barbados-dollar',
],
'BDT' => [
'BDT',
'Bangladesjiese taka',
],
'BGN' => [
'BGN',
'Bulgaarse lev',
],
'BHD' => [
'BHD',
'Bahreinse dinar',
],
'BIF' => [
'BIF',
'Burundiese frank',
],
'BMD' => [
'BMD',
'Bermuda-dollar',
],
'BND' => [
'BND',
'Broeneise dollar',
],
'BOB' => [
'BOB',
'Boliviaanse boliviano',
],
'BRL' => [
'R$',
'Brasilliaanse reaal',
],
'BSD' => [
'BSD',
'Bahamiaanse dollar',
],
'BTN' => [
'BTN',
'Bhoetanese ngoeltroem',
],
'BWP' => [
'BWP',
'Botswana-pula',
],
'BYN' => [
'BYN',
'Belarusiese roebel',
],
'BYR' => [
'BYR',
'Belo-Russiese roebel (20002016)',
],
'BZD' => [
'BZD',
'Beliziese dollar',
],
'CAD' => [
'CAD',
'Kanadese dollar',
],
'CDF' => [
'CDF',
'Kongolese frank',
],
'CHF' => [
'CHF',
'Switserse frank',
],
'CLP' => [
'CLP',
'Chileense peso',
],
'CNH' => [
'CNH',
'Chinese joean (buiteland)',
],
'CNY' => [
'CN¥',
'Chinese joean',
],
'COP' => [
'COP',
'Colombiaanse peso',
],
'CRC' => [
'CRC',
'Costa Ricaanse colón',
],
'CUC' => [
'CUC',
'Kubaanse omskakelbare peso',
],
'CUP' => [
'CUP',
'Kubaanse peso',
],
'CVE' => [
'CVE',
'Kaap Verdiese escudo',
],
'CZK' => [
'CZK',
'Tsjeggiese kroon',
],
'DJF' => [
'DJF',
'Djiboeti-frank',
],
'DKK' => [
'DKK',
'Deense kroon',
],
'DOP' => [
'DOP',
'Dominikaanse peso',
],
'DZD' => [
'DZD',
'Algeriese dinar',
],
'EGP' => [
'EGP',
'Egiptiese pond',
],
'ERN' => [
'ERN',
'Eritrese nakfa',
],
'ETB' => [
'ETB',
'Etiopiese birr',
],
'EUR' => [
'€',
'Euro',
],
'FJD' => [
'FJD',
'Fidjiaanse dollar',
],
'FKP' => [
'FKP',
'Falkland-eilandse pond',
],
'GBP' => [
'£',
'Britse pond',
],
'GEL' => [
'GEL',
'Georgiese lari',
],
'GHC' => [
'GHC',
'Ghanese cedi (19792007)',
],
'GHS' => [
'GHS',
'Ghanese cedi',
],
'GIP' => [
'GIP',
'Gibraltarese pond',
],
'GMD' => [
'GMD',
'Gambiese dalasi',
],
'GNF' => [
'GNF',
'Guinese frank',
],
'GNS' => [
'GNS',
'Guinese syli',
],
'GTQ' => [
'GTQ',
'Guatemalaanse kwetsal',
],
'GYD' => [
'GYD',
'Guyanese dollar',
],
'HKD' => [
'HK$',
'Hongkongse dollar',
],
'HNL' => [
'HNL',
'Hondurese lempira',
],
'HRK' => [
'HRK',
'Kroatiese kuna',
],
'HTG' => [
'HTG',
'Haïtiaanse gourde',
],
'HUF' => [
'HUF',
'Hongaarse florint',
],
'IDR' => [
'IDR',
'Indonesiese roepia',
],
'ILS' => [
'₪',
'Israeliese nuwe sikkel',
],
'INR' => [
'₹',
'Indiese roepee',
],
'IQD' => [
'IQD',
'Irakse dinar',
],
'IRR' => [
'IRR',
'Iranse rial',
],
'ISK' => [
'ISK',
'Yslandse kroon',
],
'ITL' => [
'ITL',
'Italiaanse lier',
],
'JMD' => [
'JMD',
'Jamaikaanse dollar',
],
'JOD' => [
'JOD',
'Jordaniese dinar',
],
'JPY' => [
'JP¥',
'Japannese jen',
],
'KES' => [
'KES',
'Keniaanse sjieling',
],
'KGS' => [
'KGS',
'Kirgisiese som',
],
'KHR' => [
'KHR',
'Kambodjaanse riel',
],
'KMF' => [
'KMF',
'Comoraanse frank',
],
'KPW' => [
'KPW',
'Noord-Koreaanse won',
],
'KRW' => [
'₩',
'Suid-Koreaanse won',
],
'KWD' => [
'KWD',
'Koeweitse dinar',
],
'KYD' => [
'KYD',
'Cayman-eilandse dollar',
],
'KZT' => [
'KZT',
'Kazakse tenge',
],
'LAK' => [
'LAK',
'Laosiaanse kip',
],
'LBP' => [
'LBP',
'Libanese pond',
],
'LKR' => [
'LKR',
'Sri Lankaanse roepee',
],
'LRD' => [
'LRD',
'Liberiese dollar',
],
'LSL' => [
'LSL',
'Lesotho loti',
],
'LTL' => [
'LTL',
'Litause litas',
],
'LVL' => [
'LVL',
'Lettiese lats',
],
'LYD' => [
'LYD',
'Libiese dinar',
],
'MAD' => [
'MAD',
'Marokkaanse dirham',
],
'MDL' => [
'MDL',
'Moldowiese leu',
],
'MGA' => [
'MGA',
'Malgassiese ariary',
],
'MKD' => [
'MKD',
'Macedoniese denar',
],
'MMK' => [
'MMK',
'Mianmese kyat',
],
'MNT' => [
'MNT',
'Mongoolse toegrik',
],
'MOP' => [
'MOP',
'Macaose pataca',
],
'MRO' => [
'MRO',
'Mauritaniese ouguiya (19732017)',
],
'MRU' => [
'MRU',
'Mauritaniese ouguiya',
],
'MUR' => [
'MUR',
'Mauritiaanse roepee',
],
'MVR' => [
'MVR',
'Malediviese rufia',
],
'MWK' => [
'MWK',
'Malawiese kwacha',
],
'MXN' => [
'MXN',
'Meksikaanse peso',
],
'MYR' => [
'MYR',
'Maleisiese ringgit',
],
'MZM' => [
'MZM',
'Mosambiekse metical (19802006)',
],
'MZN' => [
'MZN',
'Mosambiekse metical',
],
'NAD' => [
'NAD',
'Namibiese dollar',
],
'NGN' => [
'NGN',
'Nigeriese naira',
],
'NIO' => [
'NIO',
'Nicaraguaanse córdoba',
],
'NOK' => [
'NOK',
'Noorse kroon',
],
'NPR' => [
'NPR',
'Nepalese roepee',
],
'NZD' => [
'NZ$',
'Nieu-Seelandse dollar',
],
'OMR' => [
'OMR',
'Omaanse rial',
],
'PAB' => [
'PAB',
'Panamese balboa',
],
'PEN' => [
'PEN',
'Peruaanse sol',
],
'PGK' => [
'PGK',
'Papoea-Nieu-Guinese kina',
],
'PHP' => [
'PHP',
'Filippynse peso',
],
'PKR' => [
'PKR',
'Pakistanse roepee',
],
'PLN' => [
'PLN',
'Poolse zloty',
],
'PYG' => [
'PYG',
'Paraguaanse guarani',
],
'QAR' => [
'QAR',
'Katarrese rial',
],
'RON' => [
'RON',
'Roemeense leu',
],
'RSD' => [
'RSD',
'Serwiese dinar',
],
'RUB' => [
'RUB',
'Russiese roebel',
],
'RWF' => [
'RWF',
'Rwandese frank',
],
'SAR' => [
'SAR',
'Saoedi-Arabiese riyal',
],
'SBD' => [
'SBD',
'Salomonseilandse dollar',
],
'SCR' => [
'SCR',
'Seychellese roepee',
],
'SDG' => [
'SDG',
'Soedannese pond',
],
'SDP' => [
'SDP',
'Soedannese pond (19571998)',
],
'SEK' => [
'SEK',
'Sweedse kroon',
],
'SGD' => [
'SGD',
'Singapoer-dollar',
],
'SHP' => [
'SHP',
'Sint Helena-pond',
],
'SLE' => [
'SLE',
'Sierra Leoniese leone',
],
'SLL' => [
'SLL',
'Sierra Leoniese leone (1964—2022)',
],
'SOS' => [
'SOS',
'Somaliese sjieling',
],
'SRD' => [
'SRD',
'Surinaamse dollar',
],
'SSP' => [
'SSP',
'Suid-Soedanese pond',
],
'STD' => [
'STD',
'São Tomé en Príncipe dobra (19772017)',
],
'STN' => [
'STN',
'São Tomé en Príncipe-dobra',
],
'SYP' => [
'SYP',
'Siriese pond',
],
'SZL' => [
'SZL',
'Swazilandse lilangeni',
],
'THB' => [
'฿',
'Thaise baht',
],
'TJS' => [
'TJS',
'Tadjikse somoni',
],
'TMT' => [
'TMT',
'Turkmeense manat',
],
'TND' => [
'TND',
'Tunisiese dinar',
],
'TOP' => [
'TOP',
'Tongaanse paanga',
],
'TRL' => [
'TRL',
'Turkse lier (19222005)',
],
'TRY' => [
'TRY',
'Turkse lira',
],
'TTD' => [
'TTD',
'Trinidad en Tobago-dollar',
],
'TWD' => [
'NT$',
'Nuwe Taiwanese dollar',
],
'TZS' => [
'TZS',
'Tanzaniese sjieling',
],
'UAH' => [
'UAH',
'Oekraïnse hriwna',
],
'UGX' => [
'UGX',
'Ugandese sjieling',
],
'USD' => [
'USD',
'VSA-dollar',
],
'UYU' => [
'UYU',
'Uruguaanse peso',
],
'UZS' => [
'UZS',
'Oezbekiese som',
],
'VEF' => [
'VEF',
'Venezolaanse bolivar',
],
'VES' => [
'VES',
'Venezolaanse bolívar',
],
'VND' => [
'₫',
'Viëtnamese dong',
],
'VUV' => [
'VUV',
'Vanuatuse vatu',
],
'WST' => [
'WST',
'Samoaanse tala',
],
'XAF' => [
'FCFA',
'Sentraal Afrikaanse CFA-frank',
],
'XCD' => [
'EC$',
'Oos-Karibiese dollar',
],
'XOF' => [
'FCFA',
'Wes-Afrikaanse CFA-frank',
],
'XPF' => [
'CFPF',
'CFP-frank',
],
'YER' => [
'YER',
'Jemenitiese rial',
],
'ZAR' => [
'R',
'Suid-Afrikaanse rand',
],
'ZMK' => [
'ZMK',
'Zambiese kwacha (19682012)',
],
'ZMW' => [
'ZMW',
'Zambiese kwacha',
],
'ZWD' => [
'ZWD',
'Zimbabwiese dollar',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'NAD' => [
'$',
'Namibiese dollar',
],
],
];

View File

@@ -0,0 +1,666 @@
<?php
return [
'Names' => [
'AED' => [
'AED',
'Ɛmirete Arab Nkabɔmu Deram',
],
'AFN' => [
'AFN',
'Afghanfoɔ Afghani',
],
'ALL' => [
'ALL',
'Albania Lek',
],
'AMD' => [
'AMD',
'Amɛnia dram',
],
'ANG' => [
'ANG',
'Nɛdɛlande Antɛlia guuda',
],
'AOA' => [
'AOA',
'Angola Kwanza',
],
'ARS' => [
'ARS',
'Agɛntina peso',
],
'AUD' => [
'A$',
'Ɔstrelia Dɔla',
],
'AWG' => [
'AWG',
'Aruba flɔrin',
],
'AZN' => [
'AZN',
'Azɛbagyan manat',
],
'BAM' => [
'BAM',
'Bɔsnia-Hɛzegɔvina nsesa maake',
],
'BBD' => [
'BBD',
'Babadɔso dɔla',
],
'BDT' => [
'BDT',
'Bangladehye taka',
],
'BGN' => [
'BGN',
'Bɔɔgaria lɛv',
],
'BHD' => [
'BHD',
'Baren Dina',
],
'BIF' => [
'BIF',
'Burundi Frank',
],
'BMD' => [
'BMD',
'Bɛɛmuda dɔla',
],
'BND' => [
'BND',
'Brunei dɔla',
],
'BOB' => [
'BOB',
'Bolivia boliviano',
],
'BRL' => [
'R$',
'Brazil reale',
],
'BSD' => [
'BSD',
'Bahama dɔla',
],
'BTN' => [
'BTN',
'Butanfoɔ ngutrum',
],
'BWP' => [
'BWP',
'Botswana Pula',
],
'BYN' => [
'BYN',
'Bɛlaruhyia ruble',
],
'BZD' => [
'BZD',
'Belize Dɔla',
],
'CAD' => [
'CA$',
'Kanada Dɔla',
],
'CDF' => [
'CDF',
'Kongo Frank',
],
'CHF' => [
'CHF',
'Swiss Franc',
],
'CLP' => [
'CLP',
'Kyili Peso',
],
'CNH' => [
'CNH',
'kyaena yuan (offshore)',
],
'CNY' => [
'CN¥',
'kyaena yuan',
],
'COP' => [
'COP',
'Kolombia peso',
],
'CRC' => [
'CRC',
'Kɔsta Rika kɔlɔn',
],
'CUC' => [
'CUC',
'Kuba nsesa peso',
],
'CUP' => [
'CUP',
'Kuba peso',
],
'CVE' => [
'CVE',
'Ɛskudo',
],
'CZK' => [
'CZK',
'Kyɛk koruna',
],
'DJF' => [
'DJF',
'Gyebuti Frank',
],
'DKK' => [
'DKK',
'Danefoɔ krone',
],
'DOP' => [
'DOP',
'Dɔmenika peso',
],
'DZD' => [
'DZD',
'Ɔlgyeria Dina',
],
'EGP' => [
'EGP',
'Egypt Pɔn',
],
'ERN' => [
'ERN',
'Ɛretereya Nakfa',
],
'ETB' => [
'ETB',
'Itiopia Bir',
],
'EUR' => [
'€',
'Iro',
],
'FJD' => [
'FJD',
'Figyi Dɔla',
],
'FKP' => [
'FKP',
'Fɔkland Aelande Pɔn',
],
'GBP' => [
'£',
'Breten Pɔn',
],
'GEL' => [
'GEL',
'Gyɔɔgyia lari',
],
'GHC' => [
'GHC',
'Ghana Sidi (19792007)',
],
'GHS' => [
'GH₵',
'Ghana Sidi',
],
'GIP' => [
'GIP',
'Gyebrotaa pɔn',
],
'GMD' => [
'GMD',
'Gambia Dalasi',
],
'GNF' => [
'GNF',
'Gini franke',
],
'GNS' => [
'GNS',
'Gini Frank',
],
'GTQ' => [
'GTQ',
'Guatemala kwɛtsaa',
],
'GYD' => [
'GYD',
'Gayana dɔla',
],
'HKD' => [
'HK$',
'Hɔnkɔn Dɔla',
],
'HNL' => [
'HNL',
'Hɔndura lɛmpira',
],
'HRK' => [
'HRK',
'Krohyia kuna',
],
'HTG' => [
'HTG',
'Haiti gɔɔde',
],
'HUF' => [
'HUF',
'Hangari fɔrint',
],
'IDR' => [
'IDR',
'Indɔnihyia rupia',
],
'ILS' => [
'₪',
'Israel hyekel foforɔ',
],
'INR' => [
'₹',
'India Rupi',
],
'IQD' => [
'Irak dinaa',
'Irak dinaa',
],
'IRR' => [
'IRR',
'Yiranfoɔ rial',
],
'ISK' => [
'ISK',
'Icelandfoɔ Króna',
],
'JMD' => [
'JMD',
'Gyameka dɔla',
],
'JOD' => [
'JOD',
'Gyɔɔdan dinaa',
],
'JPY' => [
'JP¥',
'Gyapan Yɛn',
],
'KES' => [
'KES',
'Kenya Hyelen',
],
'KGS' => [
'KGS',
'Kagyɛstan som',
],
'KHR' => [
'KHR',
'Kambodia riel',
],
'KMF' => [
'KMF',
'Komoro Frank',
],
'KPW' => [
'KPW',
'Korea Atifi won',
],
'KRW' => [
'₩',
'Korea Anaafoɔ won',
],
'KWD' => [
'KWD',
'Kuwait dinaa',
],
'KYD' => [
'KYD',
'Kayemanfo Aelande dɔla',
],
'KZT' => [
'KZT',
'Kagyastan tenge',
],
'LAK' => [
'LAK',
'Laohyia kip',
],
'LBP' => [
'LBP',
'Lɛbanon pɔn',
],
'LKR' => [
'LKR',
'Sri Lankafoɔ rupee',
],
'LRD' => [
'LRD',
'Laeberia Dɔla',
],
'LSL' => [
'LSL',
'Lesoto Loti',
],
'LYD' => [
'LYD',
'Libya Dina',
],
'MAD' => [
'MAD',
'Moroko Diram',
],
'MDL' => [
'MDL',
'Moldova Leu',
],
'MGA' => [
'MGA',
'Madagasi Frank',
],
'MKD' => [
'MKD',
'Masidonia denaa',
],
'MMK' => [
'MMK',
'Mayamaa kyat',
],
'MNT' => [
'MNT',
'Mongoliafoɔ tugrike',
],
'MOP' => [
'MOP',
'Makaw pataka',
],
'MRO' => [
'MRO',
'Mɔretenia Ouguiya (19732017)',
],
'MRU' => [
'MRU',
'Mɔretenia Ouguiya',
],
'MUR' => [
'MUR',
'Mɔrehyeɔs Rupi',
],
'MVR' => [
'MVR',
'Maldivefoɔ rufiyaa',
],
'MWK' => [
'MWK',
'Malawi Kwakya',
],
'MXN' => [
'MX$',
'Mɛksiko pɛso',
],
'MYR' => [
'MYR',
'Malaahyia ringgit',
],
'MZM' => [
'MZM',
'Mozambik Metical',
],
'MZN' => [
'MZN',
'Mozambik mɛtikaa',
],
'NAD' => [
'NAD',
'Namibia Dɔla',
],
'NGN' => [
'NGN',
'Naegyeria Naira',
],
'NIO' => [
'NIO',
'Nikaragua kɔɔdɔba',
],
'NOK' => [
'NOK',
'Nɔɔwee Krone',
],
'NPR' => [
'NPR',
'Nepalfoɔ rupee',
],
'NZD' => [
'NZ$',
'New Zealand Dɔla',
],
'OMR' => [
'OMR',
'Oman rial',
],
'PAB' => [
'PAB',
'Panama baaboa',
],
'PEN' => [
'PEN',
'Pɛruvia sol',
],
'PGK' => [
'PGK',
'Papua New Gini kina',
],
'PHP' => [
'₱',
'Filipine peso',
],
'PKR' => [
'PKR',
'Pakistanfoɔ rupee',
],
'PLN' => [
'PLN',
'Pɔlihye zloty',
],
'PYG' => [
'PYG',
'Paragayana guarani',
],
'QAR' => [
'QAR',
'Kata riyaa',
],
'RON' => [
'RON',
'Romania Leu',
],
'RSD' => [
'RSD',
'Sɛɛbia dinaa',
],
'RUB' => [
'RUB',
'Rɔhyia rubuu',
],
'RWF' => [
'RWF',
'Rewanda Frank',
],
'SAR' => [
'SAR',
'Saudi Riyal',
],
'SBD' => [
'SBD',
'Solomon Aeland Dɔla',
],
'SCR' => [
'SCR',
'Seyhyɛls Rupi',
],
'SDG' => [
'SDG',
'Sudan Dina',
],
'SDP' => [
'SDP',
'Sudan Pɔn',
],
'SEK' => [
'SEK',
'Sweden Krona',
],
'SGD' => [
'SGD',
'Singapɔɔ dɔla',
],
'SHP' => [
'SHP',
'St Helena Pɔn',
],
'SLE' => [
'SLE',
'Leone',
],
'SLL' => [
'SLL',
'Leone (1964—2022)',
],
'SOS' => [
'SOS',
'Somailia Hyelen',
],
'SRD' => [
'SRD',
'Suriname dɔla',
],
'SSP' => [
'SSP',
'Sudan Anaafoɔ Pɔn',
],
'STD' => [
'STD',
'Sao Tome ne Principe Dobra (19772017)',
],
'STN' => [
'STN',
'Sao Tome ne Principe Dobra',
],
'SYP' => [
'SYP',
'Siria pɔn',
],
'SZL' => [
'SZL',
'Lilangeni',
],
'THB' => [
'THB',
'Tai bat',
],
'TJS' => [
'TJS',
'Tagyikistan somoni',
],
'TMT' => [
'TMT',
'Tɛkmɛstan manat',
],
'TND' => [
'TND',
'Tunisia Dina',
],
'TOP' => [
'TOP',
'Tonga Paʻanga',
],
'TRY' => [
'TRY',
'Tɛki lira',
],
'TTD' => [
'TTD',
'Trinidad ne Tobago dɔla',
],
'TWD' => [
'NT$',
'Taewanfoɔ dɔla foforɔ',
],
'TZS' => [
'TZS',
'Tanzania Hyelen',
],
'UAH' => [
'UAH',
'Yukren hryvnia',
],
'UGX' => [
'UGX',
'Uganda Hyelen',
],
'USD' => [
'US$',
'Amɛrika Dɔla',
],
'UYU' => [
'UYU',
'Yurugueɛ peso',
],
'UZS' => [
'UZS',
'Yusbɛkistan som',
],
'VES' => [
'VES',
'Venezuelan bolívar',
],
'VND' => [
'₫',
'Viɛtnamfoɔ dɔn',
],
'VUV' => [
'VUV',
'Vanuatu vatu',
],
'WST' => [
'WST',
'Samoa Tala',
],
'XAF' => [
'FCFA',
'Afrika Mfinimfini Sefa',
],
'XCD' => [
'EC$',
'Karibine Apueeɛ dɔla',
],
'XOF' => [
'AAS',
'Afrika Atɔeɛ Sefa',
],
'XPF' => [
'CFPF',
'CFP Franc',
],
'YER' => [
'YER',
'Yɛmɛn rial',
],
'ZAR' => [
'ZAR',
'Afrika Anaafo Rand',
],
'ZMK' => [
'ZMK',
'Zambia Kwacha (19682012)',
],
'ZMW' => [
'ZMW',
'Zambia Kwakya',
],
'ZWD' => [
'ZWD',
'Zimbabwe Dɔla',
],
],
];

View File

@@ -0,0 +1,674 @@
<?php
return [
'Names' => [
'AED' => [
'AED',
'የተባበሩት የአረብ ኤምሬትስ ድርሀም',
],
'AFN' => [
'AFN',
'የአፍጋን አፍጋኒ',
],
'ALL' => [
'ALL',
'የአልባንያ ሌክ',
],
'AMD' => [
'AMD',
'የአርመን ድራም',
],
'ANG' => [
'ANG',
'ኔዘርላንድስ አንቲሊአን ጊልደር',
],
'AOA' => [
'AOA',
'የአንጎላ ኩዋንዛ',
],
'ARS' => [
'ARS',
'የአርጀንቲና ፔሶ',
],
'AUD' => [
'AU$',
'የአውስትራሊያ ዶላር',
],
'AWG' => [
'AWG',
'አሩባን ፍሎሪን',
],
'AZN' => [
'AZN',
'የአዛርባጃን ማናት',
],
'BAM' => [
'BAM',
'የቦስኒያ ሄርዞጎቪና የሚመነዘር ማርክ',
],
'BBD' => [
'BBD',
'የባርቤዶስ ዶላር',
],
'BDT' => [
'BDT',
'የባንግላዲሽ ታካ',
],
'BGN' => [
'BGN',
'የቡልጋሪያ ሌቭ',
],
'BHD' => [
'BHD',
'የባኽሬን ዲናር',
],
'BIF' => [
'BIF',
'የብሩንዲ ፍራንክ',
],
'BMD' => [
'BMD',
'የቤርሙዳ ዶላር',
],
'BND' => [
'BND',
'የብሩኔ ዶላር',
],
'BOB' => [
'BOB',
'የቦሊቪያ ቦሊቪያኖ',
],
'BRL' => [
'R$',
'የብራዚል ሪል',
],
'BSD' => [
'BSD',
'የባሃማስ ዶላር',
],
'BTN' => [
'BTN',
'ብሁታኒዝ ንጉልትረም',
],
'BWP' => [
'BWP',
'የቦትስዋና ፑላ',
],
'BYN' => [
'BYN',
'የቤላሩስያ ሩብል',
],
'BYR' => [
'BYR',
'የቤላሩስያ ሩብል (20002016)',
],
'BZD' => [
'BZD',
'የቤሊዝ ዶላር',
],
'CAD' => [
'CA$',
'የካናዳ ዶላር',
],
'CDF' => [
'CDF',
'የኮንጐ ፍራንክ ኮንጐሌዝ',
],
'CHF' => [
'CHF',
'የስዊስ ፍራንክ',
],
'CLP' => [
'CLP',
'የቺሊ ፔሶ',
],
'CNH' => [
'CNH',
'የቻይና ዩዋን (የውጭ ምንዛሪ)',
],
'CNY' => [
'CN¥',
'የቻይና የን',
],
'COP' => [
'COP',
'የኮሎምቢያ ፔሶ',
],
'CRC' => [
'CRC',
'የኮስታሪካ ኮሎን',
],
'CUC' => [
'CUC',
'የኩባ የሚመነዘር ፔሶ',
],
'CUP' => [
'CUP',
'የኩባ ፔሶ',
],
'CVE' => [
'CVE',
'የኬፕ ቫርዲ ኤስኩዶ',
],
'CZK' => [
'CZK',
'ቼክ ሪፐብሊክ ኮሩና',
],
'DJF' => [
'DJF',
'የጅቡቲ ፍራንክ',
],
'DKK' => [
'DKK',
'የዴንማርክ ክሮን',
],
'DOP' => [
'DOP',
'የዶሚኒክ ፔሶ',
],
'DZD' => [
'DZD',
'የአልጄሪያ ዲናር',
],
'EGP' => [
'EGP',
'የግብጽ ፓውንድ',
],
'ERN' => [
'ERN',
'የኤርትራ ናቅፋ',
],
'ETB' => [
'ብር',
'የኢትዮጵያ ብር',
],
'EUR' => [
'€',
'ዩሮ',
],
'FJD' => [
'FJD',
'የፊጂ ዶላር',
],
'FKP' => [
'FKP',
'የፎክላንድ ደሴቶች ፓውንድ',
],
'GBP' => [
'£',
'የእንግሊዝ ፓውንድ ስተርሊንግ',
],
'GEL' => [
'GEL',
'የጆርጅያ ላሪ',
],
'GHC' => [
'GHC',
'የጋና ሴዲ',
],
'GHS' => [
'GHS',
'የጋና ሲዲ',
],
'GIP' => [
'GIP',
'ጂብራልተር ፓውንድ',
],
'GMD' => [
'GMD',
'የጋምቢያ ዳላሲ',
],
'GNF' => [
'GNF',
'የጊኒ ፍራንክ',
],
'GTQ' => [
'GTQ',
'ጓቲማላን ኩቲዛል',
],
'GYD' => [
'GYD',
'የጉየና ዶላር',
],
'HKD' => [
'HK$',
'የሆንግኮንግ ዶላር',
],
'HNL' => [
'HNL',
'የሃንዱራ ሌምፓአይራ',
],
'HRK' => [
'HRK',
'የክሮሽያ ኩና',
],
'HTG' => [
'HTG',
'የሃያቲ ጓርዴ',
],
'HUF' => [
'HUF',
'የሃንጋሪያን ፎሪንት',
],
'IDR' => [
'IDR',
'የኢንዶኔዥያ ሩፒሃ',
],
'ILS' => [
'₪',
'የእስራኤል አዲስ ሽቅል',
],
'INR' => [
'₹',
'የሕንድ ሩፒ',
],
'IQD' => [
'IQD',
'የኢራቅ ዲናር',
],
'IRR' => [
'IRR',
'የኢራን ሪአል',
],
'ISK' => [
'ISK',
'የአይስላንድ ክሮና',
],
'JMD' => [
'JMD',
'የጃማይካ ዶላር',
],
'JOD' => [
'JOD',
'የጆርዳን ዲናር',
],
'JPY' => [
'JP¥',
'የጃፓን የን',
],
'KES' => [
'KES',
'የኬኒያ ሺሊንግ',
],
'KGS' => [
'KGS',
'የኪርጊስታን ሶም',
],
'KHR' => [
'KHR',
'የካምቦዲያ ሬል',
],
'KMF' => [
'KMF',
'የኮሞሮ ፍራንክ',
],
'KPW' => [
'KPW',
'የሰሜን ኮሪያ ዎን',
],
'KRW' => [
'₩',
'የደቡብ ኮሪያ ዎን',
],
'KWD' => [
'KWD',
'የኩዌት ዲናር',
],
'KYD' => [
'KYD',
'የካይማን ደሴቶች ዶላር',
],
'KZT' => [
'KZT',
'የካዛኪስታን ተንጌ',
],
'LAK' => [
'LAK',
'የላኦቲ ኪፕ',
],
'LBP' => [
'LBP',
'የሊባኖስ ፓውንድ',
],
'LKR' => [
'LKR',
'የሲሪላንካ ሩፒ',
],
'LRD' => [
'LRD',
'የላይቤሪያ ዶላር',
],
'LSL' => [
'LSL',
'የሌሶቶ ሎቲ',
],
'LTL' => [
'LTL',
'ሊቱዌንያን ሊታስ',
],
'LVL' => [
'LVL',
'የላቲቫ ላትስ',
],
'LYD' => [
'LYD',
'የሊቢያ ዲናር',
],
'MAD' => [
'MAD',
'የሞሮኮ ዲርሀም',
],
'MDL' => [
'MDL',
'ሞልዶቫን ሊኡ',
],
'MGA' => [
'MGA',
'የማደጋስካር ማላጋስይ አሪያርይ',
],
'MKD' => [
'MKD',
'የሜቆድንያ ዲናር',
],
'MMK' => [
'MMK',
'የማያናማር ክያት',
],
'MNT' => [
'MNT',
'የሞንጎሊያን ቱግሪክ',
],
'MOP' => [
'MOP',
'የማካኔዝ ፓታካ',
],
'MRO' => [
'MRO',
'የሞሪቴኒያ ኦውጉያ (19732017)',
],
'MRU' => [
'MRU',
'የሞሪቴኒያ ኦውጉያ',
],
'MUR' => [
'MUR',
'የሞሪሸስ ሩፒ',
],
'MVR' => [
'MVR',
'የማልዲቫ ሩፊያ',
],
'MWK' => [
'MWK',
'የማላዊ ኩዋቻ',
],
'MXN' => [
'MX$',
'የሜክሲኮ ፔሶ',
],
'MYR' => [
'MYR',
'የማሌዥያ ሪንጊት',
],
'MZN' => [
'MZN',
'የሞዛምቢክ ሜቲካል',
],
'NAD' => [
'NAD',
'የናሚቢያ ዶላር',
],
'NGN' => [
'NGN',
'የናይጄሪያ ናይራ',
],
'NIO' => [
'NIO',
'የኒካራጓ ኮርዶባ',
],
'NOK' => [
'NOK',
'የኖርዌይ ክሮን',
],
'NPR' => [
'NPR',
'የኔፓል ሩፒ',
],
'NZD' => [
'NZ$',
'የኒውዚላንድ ዶላር',
],
'OMR' => [
'OMR',
'የኦማን ሪአል',
],
'PAB' => [
'PAB',
'ፓናማኒአን ባልቦአ',
],
'PEN' => [
'PEN',
'የፔሩቪያ ሶል',
],
'PGK' => [
'PGK',
'የፓፕዋ ኒው ጊኒ ኪና',
],
'PHP' => [
'PHP',
'የፊሊፒንስ ፔሶ',
],
'PKR' => [
'PKR',
'የፓኪስታን ሩፒ',
],
'PLN' => [
'PLN',
'የፖላንድ ዝሎቲ',
],
'PYG' => [
'PYG',
'የፓራጓይ ጉአራኒ',
],
'QAR' => [
'QAR',
'የኳታር ሪአል',
],
'RON' => [
'RON',
'የሮማኒያ ለው',
],
'RSD' => [
'RSD',
'የሰርቢያ ዲናር',
],
'RUB' => [
'RUB',
'የሩስያ ሩብል',
],
'RWF' => [
'RWF',
'የሩዋንዳ ፍራንክ',
],
'SAR' => [
'SAR',
'የሳውዲ ሪያል',
],
'SBD' => [
'SBD',
'የሰለሞን ደሴቶች ዶላር',
],
'SCR' => [
'SCR',
'የሲሼል ሩፒ',
],
'SDG' => [
'SDG',
'የሱዳን ፓውንድ',
],
'SDP' => [
'SDP',
'የሱዳን ፓውንድ (19571998)',
],
'SEK' => [
'SEK',
'የስዊድን ክሮና',
],
'SGD' => [
'SGD',
'የሲንጋፖር ዶላር',
],
'SHP' => [
'SHP',
'የሴይንት ሔሌና ፓውንድ',
],
'SLE' => [
'SLE',
'የሴራሊዎን ሊዎን',
],
'SLL' => [
'SLL',
'የሴራሊዎን ሊዎን (1964—2022)',
],
'SOS' => [
'SOS',
'የሶማሌ ሺሊንግ',
],
'SRD' => [
'SRD',
'የሰርናሜዝ ዶላር',
],
'SSP' => [
'SSP',
'የደቡብ ሱዳን ፓውንድ',
],
'STD' => [
'STD',
'የሳኦ ቶሜ እና ፕሪንሲፔ ዶብራ (19772017)',
],
'STN' => [
'STN',
'የሳኦ ቶሜ እና ፕሪንሲፔ ዶብራ',
],
'SYP' => [
'SYP',
'የሲሪያ ፓውንድ',
],
'SZL' => [
'SZL',
'የስዋዚላንድ ሊላንገኒ',
],
'THB' => [
'฿',
'የታይላንድ ባህት',
],
'TJS' => [
'TJS',
'የታጂክስታን ሶሞኒ',
],
'TMT' => [
'TMT',
'ቱርክሜኒስታኒ ማናት',
],
'TND' => [
'TND',
'የቱኒዚያ ዲናር',
],
'TOP' => [
'TOP',
'ቶንጋን ፓ’አንጋ',
],
'TRY' => [
'TRY',
'የቱርክ ሊራ',
],
'TTD' => [
'TTD',
'የትሪንዳድ እና ቶቤጎዶላር',
],
'TWD' => [
'NT$',
'የአዲሷ ታይዋን ዶላር',
],
'TZS' => [
'TZS',
'የታንዛኒያ ሺሊንግ',
],
'UAH' => [
'UAH',
'የዩክሬን ሀሪይቭኒአ',
],
'UGX' => [
'UGX',
'የዩጋንዳ ሺሊንግ',
],
'USD' => [
'US$',
'የአሜሪካን ዶላር',
],
'UYU' => [
'UYU',
'የኡራጓይ ፔሶ',
],
'UZS' => [
'UZS',
'የኡዝፔኪስታን ሶም',
],
'VEF' => [
'VEF',
'የቬንዝዌላ ቦሊቫር (20082018)',
],
'VES' => [
'VES',
'የቬንዝዌላ-ቦሊቫር',
],
'VND' => [
'₫',
'የቭየትናም ዶንግ',
],
'VUV' => [
'VUV',
'የቫንዋንቱ ቫቱ',
],
'WST' => [
'WST',
'ሳሞአን ታላ',
],
'XAF' => [
'FCFA',
'የመካከለኛው አፍሪካ ሴፋ ፍራንክ',
],
'XCD' => [
'EC$',
'የምዕራብ ካሪብያን ዶላር',
],
'XOF' => [
'FCFA',
'የምዕራብ አፍሪካ ሴፋ ፍራንክ',
],
'XPF' => [
'CFPF',
'ሲ ኤፍ ፒ ፍራንክ',
],
'YER' => [
'YER',
'የየመን ሪአል',
],
'ZAR' => [
'ZAR',
'የደቡብ አፍሪካ ራንድ',
],
'ZMK' => [
'ZMK',
'የዛምቢያ ክዋቻ (19682012)',
],
'ZMW' => [
'ZMW',
'የዛምቢያ ክዋቻ',
],
'ZWD' => [
'ZWD',
'የዚምቧቡዌ ዶላር',
],
],
];

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'DJF' => [
'Fdj',
'فرنك جيبوتي',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'ERN' => [
'Nfk',
'ناكفا أريتري',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'KMF' => [
'CF',
'فرنك جزر القمر',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'SDG' => [
'SDG',
'جنيه سوداني',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'SOS' => [
'S',
'شلن صومالي',
],
],
];

View File

@@ -0,0 +1,14 @@
<?php
return [
'Names' => [
'GBP' => [
'GB£',
'جنيه إسترليني',
],
'SSP' => [
'£',
'جنيه جنوب السودان',
],
],
];

View File

@@ -0,0 +1,650 @@
<?php
return [
'Names' => [
'AED' => [
'AED',
'সংযুক্ত আৰব আমিৰাত ডিৰহেম',
],
'AFN' => [
'AFN',
'আফগান আফগানী',
],
'ALL' => [
'ALL',
'আলবেনীয় লেক',
],
'AMD' => [
'AMD',
'আৰ্মেনিয়ান ড্ৰাম',
],
'ANG' => [
'ANG',
'নেডাৰলেণ্ডছ এণ্টিলিয়েন গিল্ডাৰ',
],
'AOA' => [
'AOA',
'এংগোলান কোৱাঞ্জা',
],
'ARS' => [
'ARS',
'আৰ্জেণ্টাইন পেছো',
],
'AUD' => [
'A$',
'অষ্ট্ৰেলিয়ান ডলাৰ',
],
'AWG' => [
'AWG',
'আৰুবান ফ্ল’ৰিন',
],
'AZN' => [
'AZN',
'আজেৰবাইজানী মানাত',
],
'BAM' => [
'BAM',
'ব’ছনিয়া আৰু হাৰ্জেগ’ভিনা কনভাৰ্টিব্‌ল মাৰ্ক',
],
'BBD' => [
'BBD',
'বাৰ্বাডিয়ান ডলাৰ',
],
'BDT' => [
'BDT',
'বাংলাদেশী টাকা',
],
'BGN' => [
'BGN',
'বুলগেৰীয় লেভ',
],
'BHD' => [
'BHD',
'বাহৰেইনী ডিনাৰ',
],
'BIF' => [
'BIF',
'বুৰুণ্ডিয়ান ফ্ৰেংক',
],
'BMD' => [
'BMD',
'বাৰ্মুডান ডলাৰ',
],
'BND' => [
'BND',
'ব্ৰুনেই ডলাৰ',
],
'BOB' => [
'BOB',
'বলিভিয়ান বলিভিয়ানো',
],
'BRL' => [
'R$',
'ব্ৰাজিলিয়ান ৰিয়েল',
],
'BSD' => [
'BSD',
'বাহামিয়ান ডলাৰ',
],
'BTN' => [
'BTN',
'ভুটানী নংগলট্ৰাম',
],
'BWP' => [
'BWP',
'ব’টচোৱানান পুলা',
],
'BYN' => [
'BYN',
'বেলাৰুছীয় ৰুবেল',
],
'BZD' => [
'BZD',
'বেলিজ ডলাৰ',
],
'CAD' => [
'CA$',
'কানাডিয়ান ডলাৰ',
],
'CDF' => [
'CDF',
'কংগো ফ্ৰেংক',
],
'CHF' => [
'CHF',
'চুইছ ফ্ৰেংক',
],
'CLP' => [
'CLP',
'চিলিয়ান পেছো',
],
'CNH' => [
'CNH',
'চীনা ইউৱান (অফশ্ব’ৰ)',
],
'CNY' => [
'CN¥',
'চীনা ইউৱান',
],
'COP' => [
'COP',
'কলম্বিয়ান পেছো',
],
'CRC' => [
'CRC',
'কোষ্টা ৰিকান কোলন',
],
'CUC' => [
'CUC',
'কিউবান ৰূপান্তৰযোগ্য পেছো',
],
'CUP' => [
'CUP',
'কিউবান পেছো',
],
'CVE' => [
'CVE',
'কেপ ভাৰ্দে এছকুডো',
],
'CZK' => [
'CZK',
'চেক কোৰুনা',
],
'DJF' => [
'DJF',
'জিবুটি ফ্ৰেংক',
],
'DKK' => [
'DKK',
'ডেনিচ ক্ৰোন',
],
'DOP' => [
'DOP',
'ড’মিনিকান পেছো',
],
'DZD' => [
'DZD',
'আলজেৰীয় ডিনাৰ',
],
'EGP' => [
'EGP',
'ইজিপ্তৰ পাউণ্ড',
],
'ERN' => [
'ERN',
'এৰিট্ৰিয়ন নাক্‌ফা',
],
'ETB' => [
'ETB',
'ইথিঅ’পিয়ান বিৰ',
],
'EUR' => [
'€',
'ইউৰো',
],
'FJD' => [
'FJD',
'ফিজিয়ান ডলাৰ',
],
'FKP' => [
'FKP',
'ফকলেণ্ড দ্বীপপুঞ্জৰ পাউণ্ড',
],
'GBP' => [
'£',
'ব্ৰিটিছ পাউণ্ড',
],
'GEL' => [
'GEL',
'জৰ্জিয়ান লাৰি',
],
'GHS' => [
'GHS',
'ঘানাৰ চেডি',
],
'GIP' => [
'GIP',
'জিব্ৰাল্টৰ পাউণ্ড',
],
'GMD' => [
'GMD',
'গাম্বিয়া ডালাছি',
],
'GNF' => [
'GNF',
'গিনি ফ্ৰেংক',
],
'GTQ' => [
'GTQ',
'গুৱাটেমালা কুৱেৎজাল',
],
'GYD' => [
'GYD',
'গায়ানিজ ডলাৰ',
],
'HKD' => [
'HK$',
'হং কং ডলাৰ',
],
'HNL' => [
'HNL',
'হোন্দুৰান লেম্পিৰা',
],
'HRK' => [
'HRK',
'ক্ৰোৱেছিয়ান কুনা',
],
'HTG' => [
'HTG',
'হাইটিয়ান গৌৰ্ড',
],
'HUF' => [
'HUF',
'হাংগেৰীয়ান ফ’ৰিণ্ট',
],
'IDR' => [
'IDR',
'ইণ্ডোনেচিয়ান ৰুপিয়াহ',
],
'ILS' => [
'₪',
'ইজৰাইলী নিউ শ্বেকেল',
],
'INR' => [
'₹',
'ভাৰতীয় ৰুপী',
],
'IQD' => [
'IQD',
'ইৰাকী ডিনাৰ',
],
'IRR' => [
'IRR',
'ইৰানীয়ান ৰিয়েল',
],
'ISK' => [
'ISK',
'আইচলেণ্ডিক ক্ৰোনা',
],
'JMD' => [
'JMD',
'জামাইকান ডলাৰ',
],
'JOD' => [
'JOD',
'জৰ্ডানিয়ান ডিনাৰ',
],
'JPY' => [
'JP¥',
'জাপানী য়েন',
],
'KES' => [
'KES',
'কেনিয়ান শ্বিলিং',
],
'KGS' => [
'KGS',
'কিৰ্গিস্তানী ছোম',
],
'KHR' => [
'KHR',
'কেম্ব’ডিয়ান ৰিয়েল',
],
'KMF' => [
'KMF',
'ক’মোৰিয়ান ফ্ৰেংক',
],
'KPW' => [
'KPW',
'উত্তৰ কোৰিয়াৰ ওৱান',
],
'KRW' => [
'₩',
'দক্ষিণ কোৰিয়াৰ ওৱান',
],
'KWD' => [
'KWD',
'কুৱেইটি ডিনাৰ',
],
'KYD' => [
'KYD',
'কেইমেন দ্বীপপুঞ্জৰ ডলাৰ',
],
'KZT' => [
'KZT',
'কাজাখস্তানী তেঞ্জ',
],
'LAK' => [
'LAK',
'লাওচিয়ান কিপ',
],
'LBP' => [
'LBP',
'লেবানীজ পাউণ্ড',
],
'LKR' => [
'LKR',
'শ্ৰীলংকান ৰুপী',
],
'LRD' => [
'LRD',
'লাইবেৰিয়ান ডলাৰ',
],
'LSL' => [
'LSL',
'লেচোথো লোটি',
],
'LYD' => [
'LYD',
'লিবিয়ান ডিনাৰ',
],
'MAD' => [
'MAD',
'মৰোক্কান ডিৰহাম',
],
'MDL' => [
'MDL',
'মোলডোভান লেউ',
],
'MGA' => [
'MGA',
'মালাগাছী এৰিয়াৰী',
],
'MKD' => [
'MKD',
'মেচিডোনীয় ডেনাৰ',
],
'MMK' => [
'MMK',
'ম্যানমাৰ কিয়াট',
],
'MNT' => [
'MNT',
'মঙ্গোলিয়ান টুৰ্গিক',
],
'MOP' => [
'MOP',
'মেকানীজ পাটাকা',
],
'MRO' => [
'MRO',
'ম’ৰিটেনিয়ান ঔগুইয়া (19732017)',
],
'MRU' => [
'MRU',
'ম’ৰিটেনিয়ান ঔগুইয়া',
],
'MUR' => [
'MUR',
'মৰিচিয়ান ৰুপী',
],
'MVR' => [
'MVR',
'মালডিভিয়ান ৰুফিয়া',
],
'MWK' => [
'MWK',
'মালাউইয়ান কোৱাচা',
],
'MXN' => [
'MX$',
'মেক্সিকান পেছো',
],
'MYR' => [
'MYR',
'মালায়েচিয়ান ৰিংগিট',
],
'MZN' => [
'MZN',
'মোজাম্বিকান মেটিকল',
],
'NAD' => [
'NAD',
'নামিবিয়ান ডলাৰ',
],
'NGN' => [
'NGN',
'নাইজেৰিয়ান নাইৰা',
],
'NIO' => [
'NIO',
'নিকাৰাগুৱান কোৰ্ডোবা',
],
'NOK' => [
'NOK',
'নৰৱেজিয়ান ক্ৰোন',
],
'NPR' => [
'NPR',
'নেপালী ৰুপী',
],
'NZD' => [
'NZ$',
'নিউজিলেণ্ড ডলাৰ',
],
'OMR' => [
'OMR',
'ওমানি ৰিয়েল',
],
'PAB' => [
'PAB',
'পানামেনিয়ান বাল্বোৱা',
],
'PEN' => [
'PEN',
'পেৰুভিয়ান ছ’ল',
],
'PGK' => [
'PGK',
'পাপুৱা নিউ গিনি কিনা',
],
'PHP' => [
'PHP',
'ফিলিপিন পেইছ’',
],
'PKR' => [
'PKR',
'পাকিস্তানী ৰুপী',
],
'PLN' => [
'PLN',
'প’লিচ জোল্টী',
],
'PYG' => [
'PYG',
'পাৰাগুয়ান গুৱাৰানি',
],
'QAR' => [
'QAR',
'কাটাৰি ৰিয়েল',
],
'RON' => [
'RON',
'ৰোমানীয় লেউ',
],
'RSD' => [
'RSD',
'চাৰ্বিয়ান ডিনাৰ',
],
'RUB' => [
'RUB',
'ৰাছিয়ান ৰুব্‌ল',
],
'RWF' => [
'RWF',
'ৰোৱান্দান ফ্ৰেংক',
],
'SAR' => [
'SAR',
'চৌডি ৰিয়েল',
],
'SBD' => [
'SBD',
'চোলোমোন দ্বীপপুঞ্জৰ ডলাৰ',
],
'SCR' => [
'SCR',
'ছেচেলৱা ৰুপী',
],
'SDG' => [
'SDG',
'চুডানী পাউণ্ড',
],
'SEK' => [
'SEK',
'চুইডিছ ক্ৰোনা',
],
'SGD' => [
'SGD',
'ছিংগাপুৰ ডলাৰ',
],
'SHP' => [
'SHP',
'ছেইণ্ট হেলেনা পাউণ্ড',
],
'SLE' => [
'SLE',
'চিয়েৰা লিঅ’নৰ লিঅ’ন',
],
'SLL' => [
'SLL',
'চিয়েৰা লিঅ’নৰ লিঅ’ন (1964—2022)',
],
'SOS' => [
'SOS',
'চোমালি শ্বিলিং',
],
'SRD' => [
'SRD',
'ছুৰিনামী ডলাৰ',
],
'SSP' => [
'SSP',
'দক্ষিণ চুডানীজ পাউণ্ড',
],
'STD' => [
'STD',
'চাও টোমে আৰু প্ৰিনচিপে ডোব্‌ৰা (19772017)',
],
'STN' => [
'STN',
'চাও টোমে আৰু প্ৰিনচিপে ডোব্‌ৰা',
],
'SYP' => [
'SYP',
'চিৰিয়ান পাউণ্ড',
],
'SZL' => [
'SZL',
'স্বাজি লিলেংগেনি',
],
'THB' => [
'THB',
'থাই বাত',
],
'TJS' => [
'TJS',
'তাজিকিস্তানী ছোমনি',
],
'TMT' => [
'TMT',
'তুৰ্কমেনিস্তানী মানাত',
],
'TND' => [
'TND',
'টুনিচিয়ান ডিনাৰ',
],
'TOP' => [
'TOP',
'টংগান পাআংগা',
],
'TRY' => [
'TRY',
'তুৰ্কীৰ লিৰা',
],
'TTD' => [
'TTD',
'ট্ৰিনিডাড আৰু টোবাগো ডলাৰ',
],
'TWD' => [
'NT$',
'নিউ টাইৱান ডলাৰ',
],
'TZS' => [
'TZS',
'টানজানিয়ান শ্বিলিং',
],
'UAH' => [
'UAH',
'ইউক্ৰেইনীয় হৃভনিয়া',
],
'UGX' => [
'UGX',
'উগাণ্ডান শ্বিলিং',
],
'USD' => [
'US$',
'ইউ. এছ. ডলাৰ',
],
'UYU' => [
'UYU',
'উৰুগুৱেয়ান পেছো',
],
'UZS' => [
'UZS',
'উজবেকিস্তানী ছোম',
],
'VEB' => [
'VEB',
'ভেনিজুৱেলান বলিভাৰ (18712008)',
],
'VEF' => [
'VEF',
'ভেনিজুৱেলান বলিভাৰ (20082018)',
],
'VES' => [
'VES',
'ভেনিজুৱেলান বলিভাৰ',
],
'VND' => [
'₫',
'ভিয়েটনামীজ ডং',
],
'VUV' => [
'VUV',
'ভানাটুৰ ভাটু',
],
'WST' => [
'WST',
'ছামোৱান টালা',
],
'XAF' => [
'FCFA',
'মধ্য আফ্ৰিকান CFA ফ্ৰেংক',
],
'XCD' => [
'EC$',
'ইষ্ট কেৰিবিয়ান ডলাৰ',
],
'XOF' => [
'FCFA',
'পশ্চিম আফ্ৰিকান CFA ফ্ৰেংক',
],
'XPF' => [
'CFPF',
'CFP ফ্ৰেংক',
],
'YER' => [
'YER',
'য়েমেনী ৰিয়েল',
],
'ZAR' => [
'ZAR',
'দক্ষিণ আফ্ৰিকাৰ ৰাণ্ড',
],
'ZMW' => [
'ZMW',
'জাম্বিয়ান কোৱাচা',
],
],
];

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'AZN' => [
'₼',
'AZN',
],
],
];

View File

@@ -0,0 +1,650 @@
<?php
return [
'Names' => [
'AED' => [
'AED',
'дырхам ААЭ',
],
'AFN' => [
'AFN',
'афганскі афгані',
],
'ALL' => [
'ALL',
'албанскі лек',
],
'AMD' => [
'AMD',
'армянскі драм',
],
'ANG' => [
'ANG',
'нідэрландскі антыльскі гульдэн',
],
'AOA' => [
'AOA',
'ангольская кванза',
],
'ARS' => [
'ARS',
'аргенцінскае песа',
],
'AUD' => [
'A$',
'аўстралійскі долар',
],
'AWG' => [
'AWG',
'арубанскі фларын',
],
'AZN' => [
'AZN',
'азербайджанскі манат',
],
'BAM' => [
'BAM',
'канверсоўная марка Босніі і Герцагавіны',
],
'BBD' => [
'BBD',
'барбадаскі долар',
],
'BDT' => [
'BDT',
'бангладэшская така',
],
'BGN' => [
'BGN',
'балгарскі леў',
],
'BHD' => [
'BHD',
'бахрэйнскі дынар',
],
'BIF' => [
'BIF',
'бурундзійскі франк',
],
'BMD' => [
'BMD',
'бермудскі долар',
],
'BND' => [
'BND',
'брунейскі долар',
],
'BOB' => [
'BOB',
'балівіяна',
],
'BRL' => [
'BRL',
'бразільскі рэал',
],
'BSD' => [
'BSD',
'багамскі долар',
],
'BTN' => [
'BTN',
'бутанскі нгултрум',
],
'BWP' => [
'BWP',
'батсванская пула',
],
'BYN' => [
'Br',
'беларускі рубель',
],
'BYR' => [
'BYR',
'беларускі рубель (20002016)',
],
'BZD' => [
'BZD',
'белізскі долар',
],
'CAD' => [
'CAD',
'канадскі долар',
],
'CDF' => [
'CDF',
'кангалезскі франк',
],
'CHF' => [
'CHF',
'швейцарскі франк',
],
'CLP' => [
'CLP',
'чылійскае песа',
],
'CNH' => [
'CNH',
'афшорны кітайскі юань',
],
'CNY' => [
'CN¥',
'кітайскі юань',
],
'COP' => [
'COP',
'калумбійскае песа',
],
'CRC' => [
'CRC',
'коста-рыканскі калон',
],
'CUC' => [
'CUC',
'кубінскае канверсоўнае песа',
],
'CUP' => [
'CUP',
'кубінскае песа',
],
'CVE' => [
'CVE',
'эскуда Каба-Вердэ',
],
'CZK' => [
'CZK',
'чэшская крона',
],
'DJF' => [
'DJF',
'джыбуційскі франк',
],
'DKK' => [
'DKK',
'дацкая крона',
],
'DOP' => [
'DOP',
'дамініканскае песа',
],
'DZD' => [
'DZD',
'алжырскі дынар',
],
'EGP' => [
'EGP',
'егіпецкі фунт',
],
'ERN' => [
'ERN',
'эрытрэйская накфа',
],
'ETB' => [
'ETB',
'эфіопскі быр',
],
'EUR' => [
'€',
'еўра',
],
'FJD' => [
'FJD',
'фіджыйскі долар',
],
'FKP' => [
'FKP',
'фунт Фалклендскіх астравоў',
],
'GBP' => [
'£',
'брытанскі фунт стэрлінгаў',
],
'GEL' => [
'GEL',
'грузінскі лары',
],
'GHS' => [
'GHS',
'ганскі седзі',
],
'GIP' => [
'GIP',
'гібралтарскі фунт',
],
'GMD' => [
'GMD',
'гамбійскі даласі',
],
'GNF' => [
'GNF',
'гвінейскі франк',
],
'GTQ' => [
'GTQ',
'гватэмальскі кетсаль',
],
'GYD' => [
'GYD',
'гаянскі долар',
],
'HKD' => [
'HK$',
'ганконгскі долар',
],
'HNL' => [
'HNL',
'гандураская лемпіра',
],
'HRK' => [
'HRK',
'харвацкая куна',
],
'HTG' => [
'HTG',
'гаіцянскі гурд',
],
'HUF' => [
'HUF',
'венгерскі форынт',
],
'IDR' => [
'IDR',
'інданезійская рупія',
],
'ILS' => [
'₪',
'новы ізраільскі шэкель',
],
'INR' => [
'₹',
'індыйская рупія',
],
'IQD' => [
'IQD',
'іракскі дынар',
],
'IRR' => [
'IRR',
'іранскі рыял',
],
'ISK' => [
'ISK',
'ісландская крона',
],
'JMD' => [
'JMD',
'ямайскі долар',
],
'JOD' => [
'JOD',
'іарданскі дынар',
],
'JPY' => [
'¥',
'японская іена',
],
'KES' => [
'KES',
'кенійскі шылінг',
],
'KGS' => [
'KGS',
'кіргізскі сом',
],
'KHR' => [
'KHR',
'камбаджыйскі рыель',
],
'KMF' => [
'KMF',
'каморскі франк',
],
'KPW' => [
'KPW',
'паўночнакарэйская вона',
],
'KRW' => [
'₩',
'паўднёвакарэйская вона',
],
'KWD' => [
'KWD',
'кувейцкі дынар',
],
'KYD' => [
'KYD',
'долар Кайманавых астравоў',
],
'KZT' => [
'KZT',
'казахстанскі тэнге',
],
'LAK' => [
'LAK',
'лаоскі кіп',
],
'LBP' => [
'LBP',
'ліванскі фунт',
],
'LKR' => [
'LKR',
'шры-ланкійская рупія',
],
'LRD' => [
'LRD',
'ліберыйскі долар',
],
'LSL' => [
'LSL',
'лесоцкі лоці',
],
'LYD' => [
'LYD',
'лівійскі дынар',
],
'MAD' => [
'MAD',
'мараканскі дырхам',
],
'MDL' => [
'MDL',
'малдаўскі лей',
],
'MGA' => [
'MGA',
'малагасійскі арыяры',
],
'MKD' => [
'MKD',
'македонскі дэнар',
],
'MMK' => [
'MMK',
'м’янманскі к’ят',
],
'MNT' => [
'MNT',
'мангольскі тугрык',
],
'MOP' => [
'MOP',
'патака Макаа',
],
'MRO' => [
'MRO',
'маўрытанская ўгія (19732017)',
],
'MRU' => [
'MRU',
'маўрытанская угія',
],
'MUR' => [
'MUR',
'маўрыкійская рупія',
],
'MVR' => [
'MVR',
'мальдыўская руфія',
],
'MWK' => [
'MWK',
'малавійская квача',
],
'MXN' => [
'MX$',
'мексіканскае песа',
],
'MYR' => [
'MYR',
'малайзійскі рынгіт',
],
'MZN' => [
'MZN',
'мазамбікскі метыкал',
],
'NAD' => [
'NAD',
'намібійскі долар',
],
'NGN' => [
'NGN',
'нігерыйская наіра',
],
'NIO' => [
'NIO',
'нікарагуанская кордаба',
],
'NOK' => [
'NOK',
'нарвежская крона',
],
'NPR' => [
'NPR',
'непальская рупія',
],
'NZD' => [
'NZD',
'новазеландскі долар',
],
'OMR' => [
'OMR',
'аманскі рыял',
],
'PAB' => [
'PAB',
'панамскае бальбоа',
],
'PEN' => [
'PEN',
'перуанскі соль',
],
'PGK' => [
'PGK',
'кіна Папуа-Новай Гвінеі',
],
'PHP' => [
'PHP',
'філіпінскае песа',
],
'PKR' => [
'PKR',
'пакістанская рупія',
],
'PLN' => [
'PLN',
'польскі злоты',
],
'PYG' => [
'PYG',
'парагвайскі гуарані',
],
'QAR' => [
'QAR',
'катарскі рыял',
],
'RON' => [
'RON',
'румынскі лей',
],
'RSD' => [
'RSD',
'сербскі дынар',
],
'RUB' => [
'₽',
'расійскі рубель',
],
'RWF' => [
'RWF',
'руандыйскі франк',
],
'SAR' => [
'SAR',
'саудаўскі рыял',
],
'SBD' => [
'SBD',
'долар Саламонавых астравоў',
],
'SCR' => [
'SCR',
'сейшэльская рупія',
],
'SDG' => [
'SDG',
'суданскі фунт',
],
'SEK' => [
'SEK',
'шведская крона',
],
'SGD' => [
'SGD',
'сінгапурскі долар',
],
'SHP' => [
'SHP',
'фунт в-ва Святой Алены',
],
'SLE' => [
'SLE',
'сьера-леонскі леонэ',
],
'SLL' => [
'SLL',
'сьера-леонскі леонэ (1964—2022)',
],
'SOS' => [
'SOS',
'самалійскі шылінг',
],
'SRD' => [
'SRD',
'сурынамскі долар',
],
'SSP' => [
'SSP',
'паўднёвасуданскі фунт',
],
'STD' => [
'STD',
'добра Сан-Тамэ і Прынсіпі (19772017)',
],
'STN' => [
'STN',
'добра Сан-Тамэ і Прынсіпі',
],
'SYP' => [
'SYP',
'сірыйскі фунт',
],
'SZL' => [
'SZL',
'свазілендскі лілангені',
],
'THB' => [
'THB',
'тайскі бат',
],
'TJS' => [
'TJS',
'таджыкскі самані',
],
'TMT' => [
'TMT',
'туркменскі манат',
],
'TND' => [
'TND',
'туніскі дынар',
],
'TOP' => [
'TOP',
'танганская паанга',
],
'TRY' => [
'TRY',
'турэцкая ліра',
],
'TTD' => [
'TTD',
'долар Трынідада і Табага',
],
'TWD' => [
'NT$',
'новы тайваньскі долар',
],
'TZS' => [
'TZS',
'танзанійскі шылінг',
],
'UAH' => [
'UAH',
'украінская грыўня',
],
'UGX' => [
'UGX',
'угандыйскі шылінг',
],
'USD' => [
'$',
'долар ЗША',
],
'UYU' => [
'UYU',
'уругвайскае песа',
],
'UZS' => [
'UZS',
'узбекскі сум',
],
'VEF' => [
'VEF',
'венесуальскі балівар (20082018)',
],
'VES' => [
'VES',
'венесуэльскі балівар',
],
'VND' => [
'₫',
'в’етнамскі донг',
],
'VUV' => [
'VUV',
'вануацкі вату',
],
'WST' => [
'WST',
'самаанская тала',
],
'XAF' => [
'FCFA',
'цэнтральнаафрыканскі франк КФА',
],
'XCD' => [
'EC$',
'усходнекарыбскі долар',
],
'XOF' => [
'FCFA',
'заходнеафрыканскі франк КФА',
],
'XPF' => [
'CFPF',
'французскі ціхаакіянскі франк',
],
'YER' => [
'YER',
'еменскі рыал',
],
'ZAR' => [
'ZAR',
'паўднёваафрыканскі рэнд',
],
'ZMW' => [
'ZMW',
'замбійская квача',
],
],
];

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,242 @@
<?php
return [
'Names' => [
'AED' => [
'AED',
'arabu mara kafoli Diram',
],
'AOA' => [
'AOA',
'angola Kwanza',
],
'AUD' => [
'A$',
'ositirali Dolar',
],
'BHD' => [
'BHD',
'bareyini Dinar',
],
'BIF' => [
'BIF',
'burundi Fraŋ',
],
'BWP' => [
'BWP',
'bɔtisiwana Pula',
],
'CAD' => [
'CA$',
'kanada Dolar',
],
'CDF' => [
'CDF',
'kongole Fraŋ',
],
'CHF' => [
'CHF',
'suwisi Fraŋ',
],
'CNY' => [
'CN¥',
'siniwa Yuwan',
],
'CVE' => [
'CVE',
'capivɛrdi Esekudo',
],
'DJF' => [
'DJF',
'jibuti Fraŋ',
],
'DZD' => [
'DZD',
'alizeri Dinar',
],
'EGP' => [
'EGP',
'eziputi Livri',
],
'ERN' => [
'ERN',
'eritere Nafika',
],
'ETB' => [
'ETB',
'etiopi Bir',
],
'EUR' => [
'€',
'ero',
],
'GBP' => [
'£',
'angilɛ Livri',
],
'GHC' => [
'GHC',
'gana Sedi',
],
'GMD' => [
'GMD',
'gambi Dalasi',
],
'GNS' => [
'GNS',
'gine Fraŋ',
],
'INR' => [
'₹',
'Ɛndu Rupi',
],
'JPY' => [
'JP¥',
'zapɔne Yɛn',
],
'KES' => [
'KES',
'keniya Siling',
],
'KMF' => [
'KMF',
'komɔri Fraŋ',
],
'LRD' => [
'LRD',
'liberiya Dolar',
],
'LSL' => [
'LSL',
'lesoto Loti',
],
'LYD' => [
'LYD',
'libi Dinar',
],
'MAD' => [
'MAD',
'marɔku Diram',
],
'MGA' => [
'MGA',
'madagasikari Fraŋ',
],
'MRO' => [
'MRO',
'mɔritani Uguwiya (19732017)',
],
'MRU' => [
'MRU',
'mɔritani Uguwiya',
],
'MUR' => [
'MUR',
'morisi Rupi',
],
'MWK' => [
'MWK',
'malawi Kwaca',
],
'MZM' => [
'MZM',
'mozanbiki Metikali',
],
'NAD' => [
'NAD',
'namibi Dolar',
],
'NGN' => [
'NGN',
'nizeriya Nɛra',
],
'RWF' => [
'RWF',
'ruwanda Fraŋ',
],
'SAR' => [
'SAR',
'sawudiya Riyal',
],
'SCR' => [
'SCR',
'sesɛli Rupi',
],
'SDG' => [
'SDG',
'sudani Dinar',
],
'SDP' => [
'SDP',
'sudani Livri',
],
'SHP' => [
'SHP',
'Ɛlɛni-Senu Livri',
],
'SLE' => [
'SLE',
'siyeralewɔni Lewɔni',
],
'SLL' => [
'SLL',
'siyeralewɔni Lewɔni (1964—2022)',
],
'SOS' => [
'SOS',
'somali Siling',
],
'STD' => [
'STD',
'sawotome Dobra (19772017)',
],
'STN' => [
'STN',
'sawotome Dobra',
],
'SZL' => [
'SZL',
'swazilandi Lilangeni',
],
'TND' => [
'TND',
'tunizi Dinar',
],
'TZS' => [
'TZS',
'tanzani Siling',
],
'UGX' => [
'UGX',
'uganda Siling',
],
'USD' => [
'US$',
'ameriki Dolar',
],
'XAF' => [
'FCFA',
'sefa Fraŋ (BEAC)',
],
'XOF' => [
'FCFA',
'sefa Fraŋ (BCEAO)',
],
'ZAR' => [
'ZAR',
'sudafriki Randi',
],
'ZMK' => [
'ZMK',
'zambi Kwaca (19682012)',
],
'ZMW' => [
'ZMW',
'zambi Kwaca',
],
'ZWD' => [
'ZWD',
'zimbabuwe Dolar',
],
],
];

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,42 @@
<?php
return [
'Names' => [
'ANG' => [
'ANG',
'নেদারল্যান্ডস অ্যান্টিলিয়ান গিল্ডার',
],
'AWG' => [
'AWG',
'আরুবান গিল্ডার',
],
'BMD' => [
'BMD',
'বারমুডান ডলার',
],
'GTQ' => [
'GTQ',
'গুয়াতেমালান কেৎসাল',
],
'HNL' => [
'HNL',
'হন্ডুরান লেম্পিরা',
],
'HTG' => [
'HTG',
'হাইতিয়ান গুর্দ',
],
'MXN' => [
'MX$',
'মেক্সিকান পেসো',
],
'USD' => [
'$',
'মার্কিন ডলার',
],
'XCD' => [
'EC$',
'পূর্ব ক্যারিবিয়ান ডলার',
],
],
];

View File

@@ -0,0 +1,18 @@
<?php
return [
'Names' => [
'CNY' => [
'¥',
'ཡུ་ཨན་',
],
'INR' => [
'₹',
'རྒྱ་གར་སྒོར་',
],
'USD' => [
'US$',
'ཨ་རིའི་སྒོར་',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'CNY' => [
'CN¥',
'ཡུ་ཨན་',
],
],
];

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'FRF' => [
'F',
'franc francès',
],
],
];

View File

@@ -0,0 +1,642 @@
<?php
return [
'Names' => [
'AED' => [
'AED',
'Дирхам ӀЦЭ',
],
'AFN' => [
'AFN',
'ОвхӀан-пачхьалкхан афгани',
],
'ALL' => [
'ALL',
'Албанин лек',
],
'AMD' => [
'AMD',
'Эрмалойчоьнан драм',
],
'ANG' => [
'ANG',
'Нидерландин Антилин гульден',
],
'AOA' => [
'AOA',
'Анголан кванза',
],
'ARS' => [
'ARS',
'Аргентинан песо',
],
'AUD' => [
'A$',
'Австралин доллар',
],
'AWG' => [
'AWG',
'Арубан флорин',
],
'AZN' => [
'AZN',
'Азербайджанан манат',
],
'BAM' => [
'BAM',
'Боснин а, Герцеговинан а хийцалун марка',
],
'BBD' => [
'BBD',
'Барбадосан доллар',
],
'BDT' => [
'BDT',
'Бангладешан така',
],
'BGN' => [
'BGN',
'Болгарин лев',
],
'BHD' => [
'BHD',
'Бахрейнан динар',
],
'BIF' => [
'BIF',
'Бурундин франк',
],
'BMD' => [
'BMD',
'Бермудан доллар',
],
'BND' => [
'BND',
'Брунейн доллар',
],
'BOB' => [
'BOB',
'Боливин боливиано',
],
'BRL' => [
'R$',
'Бразилин реал',
],
'BSD' => [
'BSD',
'Багаман доллар',
],
'BTN' => [
'BTN',
'Бутанан нгултрум',
],
'BWP' => [
'BWP',
'Ботсванан пула',
],
'BYN' => [
'BYN',
'Белоруссин сом',
],
'BYR' => [
'BYR',
'Белоруссин сом (20002016)',
],
'BZD' => [
'BZD',
'Белизин доллар',
],
'CAD' => [
'CA$',
'Канадан доллар',
],
'CDF' => [
'CDF',
'Конголезин франк',
],
'CHF' => [
'CHF',
'Швейцарин франк',
],
'CLP' => [
'CLP',
'Чилин песо',
],
'CNY' => [
'CN¥',
'Китайн юань',
],
'COP' => [
'COP',
'Колумбин песо',
],
'CRC' => [
'CRC',
'Костарикан колон',
],
'CUC' => [
'CUC',
'Кубан хийцалун песо',
],
'CUP' => [
'CUP',
'Кубан песо',
],
'CVE' => [
'CVE',
'Кабо-Верден эскудо',
],
'CZK' => [
'CZK',
'Чехин крона',
],
'DJF' => [
'DJF',
'Джибутин франк',
],
'DKK' => [
'DKK',
'Данин крона',
],
'DOP' => [
'DOP',
'Доминикан песо',
],
'DZD' => [
'DZD',
'Алжиран динар',
],
'EGP' => [
'EGP',
'Мисаран фунт',
],
'ERN' => [
'ERN',
'Эритрейн накфа',
],
'ETB' => [
'ETB',
'Эфиопин быр',
],
'EUR' => [
'€',
'Евро',
],
'FJD' => [
'FJD',
'Фиджин доллар',
],
'FKP' => [
'FKP',
'Фолклендан гӀайренийн фунт',
],
'GBP' => [
'£',
'Англин фунт',
],
'GEL' => [
'GEL',
'Гуьржийчоьнан лари',
],
'GHS' => [
'GHS',
'Ганан седи',
],
'GIP' => [
'GIP',
'Гибралтаран фунт',
],
'GMD' => [
'GMD',
'Гамбин даласи',
],
'GNF' => [
'GNF',
'Гвинейн франк',
],
'GTQ' => [
'GTQ',
'Гватемалан кетсаль',
],
'GYD' => [
'GYD',
'Гайанан доллар',
],
'HKD' => [
'HK$',
'Гонконган доллар',
],
'HNL' => [
'HNL',
'Гондурасан лемпира',
],
'HRK' => [
'HRK',
'Хорватин куна',
],
'HTG' => [
'HTG',
'Гаитин гурд',
],
'HUF' => [
'HUF',
'Венгрин форинт',
],
'IDR' => [
'IDR',
'Индонезин рупи',
],
'ILS' => [
'₪',
'Израилан керла шекель',
],
'INR' => [
'₹',
'Индин рупи',
],
'IQD' => [
'IQD',
'Ӏиракъан динар',
],
'IRR' => [
'IRR',
'ГӀажарийчоьнан риал',
],
'ISK' => [
'ISK',
'Исландин крона',
],
'JMD' => [
'JMD',
'Ямайн доллар',
],
'JOD' => [
'JOD',
'Урданан динар',
],
'JPY' => [
'JP¥',
'Японин иена',
],
'KES' => [
'KES',
'Кенин шиллинг',
],
'KGS' => [
'KGS',
'Киргизин сом',
],
'KHR' => [
'KHR',
'Камбоджан риель',
],
'KMF' => [
'KMF',
'Коморийн гӀайренийн франк',
],
'KPW' => [
'KPW',
'Къилбаседа Корейн вона',
],
'KRW' => [
'₩',
'Къилба Корейн вона',
],
'KWD' => [
'KWD',
'Кувейтан динар',
],
'KYD' => [
'KYD',
'Кайманийн гӀайренийн доллар',
],
'KZT' => [
'KZT',
'Кхазакхстанан тенге',
],
'LAK' => [
'LAK',
'Лаосан кип',
],
'LBP' => [
'LBP',
'Ливанан фунт',
],
'LKR' => [
'LKR',
'Шри-Ланкан рупи',
],
'LRD' => [
'LRD',
'Либерин доллар',
],
'LYD' => [
'LYD',
'Ливин динар',
],
'MAD' => [
'MAD',
'Мароккон дирхам',
],
'MDL' => [
'MDL',
'Молдавин лей',
],
'MGA' => [
'MGA',
'Малагасийн ариари',
],
'MKD' => [
'MKD',
'Македонин динар',
],
'MMK' => [
'MMK',
'Мьянман кьят',
],
'MNT' => [
'MNT',
'Монголин тугрик',
],
'MOP' => [
'MOP',
'Макаон патака',
],
'MRO' => [
'MRO',
'Мавританин уги (19732017)',
],
'MRU' => [
'MRU',
'Мавританин уги',
],
'MUR' => [
'MUR',
'Маврикин рупи',
],
'MVR' => [
'MVR',
'Мальдивийн руфи',
],
'MWK' => [
'MWK',
'Малавин квача',
],
'MXN' => [
'MX$',
'Мексикан песо',
],
'MYR' => [
'MYR',
'Малайзин ринггит',
],
'MZN' => [
'MZN',
'Мозамбикан метикал',
],
'NAD' => [
'NAD',
'Намибин доллар',
],
'NGN' => [
'NGN',
'Нигерин найра',
],
'NIO' => [
'NIO',
'Никарагуан кордоба',
],
'NOK' => [
'NOK',
'Норвегин крона',
],
'NPR' => [
'NPR',
'Непалан рупи',
],
'NZD' => [
'NZ$',
'Керла Зеландин доллар',
],
'OMR' => [
'OMR',
'Оманан риал',
],
'PAB' => [
'PAB',
'Панаман бальбоа',
],
'PEN' => [
'PEN',
'Перун соль',
],
'PGK' => [
'PGK',
'Папуа — Керла Гвинейн кина',
],
'PHP' => [
'PHP',
'Филиппинийн песо',
],
'PKR' => [
'PKR',
'Пакистанан рупи',
],
'PLN' => [
'PLN',
'Польшан злотый',
],
'PYG' => [
'PYG',
'Парагвайн гуарани',
],
'QAR' => [
'QAR',
'Катаран риал',
],
'RON' => [
'RON',
'Румынин лей',
],
'RSD' => [
'RSD',
'Сербин динар',
],
'RUB' => [
'₽',
'Российн сом',
],
'RWF' => [
'RWF',
'Руандан франк',
],
'SAR' => [
'SAR',
'СаӀудийн Ӏаьрбийчоьнан риал',
],
'SBD' => [
'SBD',
'Соломонан гӀайренийн доллар',
],
'SCR' => [
'SCR',
'Сейшелан рупи',
],
'SDG' => [
'SDG',
'Суданан фунт',
],
'SEK' => [
'SEK',
'Швецин крона',
],
'SGD' => [
'SGD',
'Сингапуран доллар',
],
'SHP' => [
'SHP',
'Сийлахьчу Еленин гӀайрен фунт',
],
'SLE' => [
'SLE',
'Леоне',
],
'SLL' => [
'SLL',
'Леоне (1964—2022)',
],
'SOS' => [
'SOS',
'Сомалин шиллинг',
],
'SRD' => [
'SRD',
'Суринаман доллар',
],
'SSP' => [
'SSP',
'Къилба Суданан фунт',
],
'STD' => [
'STD',
'Сан-Томен а, Принсипин а добра (19772017)',
],
'STN' => [
'STN',
'Сан-Томен а, Принсипин а добра',
],
'SYP' => [
'SYP',
'Шеман фунт',
],
'SZL' => [
'SZL',
'Свазилендан лилангени',
],
'THB' => [
'THB',
'Таиландан бат',
],
'TJS' => [
'TJS',
'Таджикистанан сомони',
],
'TMT' => [
'TMT',
'Туркменин керла манат',
],
'TND' => [
'TND',
'Тунисан динар',
],
'TOP' => [
'TOP',
'Тонганан паанга',
],
'TRY' => [
'TRY',
'Туркойчоьнан лира',
],
'TTD' => [
'TTD',
'Тринидадан а, Тобагон а доллар',
],
'TWD' => [
'NT$',
'Тайванан керла доллар',
],
'TZS' => [
'TZS',
'Танзанин шиллинг',
],
'UAH' => [
'UAH',
'Украинан гривна',
],
'UGX' => [
'UGX',
'Угандан шиллинг',
],
'USD' => [
'US$',
'АЦШн доллар',
],
'UYU' => [
'UYU',
'Уругвайн песо',
],
'UZS' => [
'UZS',
'Узбекистанан сом',
],
'VEF' => [
'VEF',
'Венесуэлан боливар (20082018)',
],
'VES' => [
'VES',
'Венесуэлан боливар',
],
'VND' => [
'₫',
'Вьетнаман донг',
],
'VUV' => [
'VUV',
'Вануатун вату',
],
'WST' => [
'WST',
'Самоанан тала',
],
'XAF' => [
'FCFA',
'Юккъерчу Африкан КФА франк',
],
'XCD' => [
'EC$',
'Малхбален Карибийн доллар',
],
'XOF' => [
'FCFA',
'Малхбузен Африкан КФА франк',
],
'XPF' => [
'CFPF',
'Французийн Тийна океанан франк',
],
'YER' => [
'YER',
'Йеменан риал',
],
'ZAR' => [
'ZAR',
'Къилба-Африкин рэнд',
],
'ZMW' => [
'ZMW',
'Замбин квача',
],
],
];

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,634 @@
<?php
return [
'Names' => [
'AED' => [
'AED',
'АПЭ дирхамӗ',
],
'AFN' => [
'AFN',
'афганийӗ',
],
'ALL' => [
'ALL',
'Албани лекӗ',
],
'AMD' => [
'AMD',
'Армяни драмӗ',
],
'ANG' => [
'ANG',
'Нидерланд Антиллиан гульденӗ',
],
'AOA' => [
'AOA',
'Ангола кванзӗ',
],
'ARS' => [
'ARS',
'Аргентина песийӗ',
],
'AUD' => [
'A$',
'Австрали долларӗ',
],
'AWG' => [
'AWG',
'Аруба флоринӗ',
],
'AZN' => [
'AZN',
'Азербайджан маначӗ',
],
'BAM' => [
'BAM',
'Боснипе Герцеговина конвертланакан марки',
],
'BBD' => [
'BBD',
'Барбадос долларӗ',
],
'BDT' => [
'BDT',
'Бангладеш таки',
],
'BGN' => [
'BGN',
'Болгари левӗ',
],
'BHD' => [
'BHD',
'Бахрейн динарӗ',
],
'BIF' => [
'BIF',
'Бурунди франкӗ',
],
'BMD' => [
'BMD',
'Бермуд долларӗ',
],
'BND' => [
'BND',
'Бруней долларӗ',
],
'BOB' => [
'BOB',
'Боливи боливианӗ',
],
'BRL' => [
'R$',
'Бразили реалӗ',
],
'BSD' => [
'BSD',
'Багам долларӗ',
],
'BTN' => [
'BTN',
'Бутан нгултрумӗ',
],
'BWP' => [
'BWP',
'Ботсвана пули',
],
'BYN' => [
'BYN',
'Беларуҫ тенкӗ',
],
'BZD' => [
'BZD',
'Белиз долларӗ',
],
'CAD' => [
'CA$',
'Канада долларӗ',
],
'CDF' => [
'CDF',
'Конголези франкӗ',
],
'CHF' => [
'CHF',
'Швейцари франкӗ',
],
'CLP' => [
'CLP',
'Чили песийӗ',
],
'CNH' => [
'CNH',
'Китай офшор юанӗ',
],
'CNY' => [
'CN¥',
'Китай юанӗ',
],
'COP' => [
'COP',
'Колумби песийӗ',
],
'CRC' => [
'CRC',
'Коста-Рика колонӗ',
],
'CUC' => [
'CUC',
'Куба конвертланакан песийӗ',
],
'CUP' => [
'CUP',
'Куба песийӗ',
],
'CVE' => [
'CVE',
'Кабо-Верде эскудӗ',
],
'CZK' => [
'CZK',
'Чехи кронӗ',
],
'DJF' => [
'DJF',
'Джибути франкӗ',
],
'DKK' => [
'DKK',
'Дани кронӗ',
],
'DOP' => [
'DOP',
'Доминикан песийӗ',
],
'DZD' => [
'DZD',
'Алжир динарӗ',
],
'EGP' => [
'EGP',
'Египет фунчӗ',
],
'ERN' => [
'ERN',
'Эритрей накфӗ',
],
'ETB' => [
'ETB',
'Эфиопи бырӗ',
],
'EUR' => [
'€',
'евро',
],
'FJD' => [
'FJD',
'Фиджи долларӗ',
],
'FKP' => [
'FKP',
'Факланд утравӗсен фунчӗ',
],
'GBP' => [
'£',
'Британи фунчӗ',
],
'GEL' => [
'GEL',
'Грузи ларийӗ',
],
'GHS' => [
'GHS',
'Гана седийӗ',
],
'GIP' => [
'GIP',
'Гибралтар фунчӗ',
],
'GMD' => [
'GMD',
'Гамби даласийӗ',
],
'GNF' => [
'GNF',
'Гвиней франкӗ',
],
'GTQ' => [
'GTQ',
'Гватемала кетсалӗ',
],
'GYD' => [
'GYD',
'Гайана долларӗ',
],
'HKD' => [
'HK$',
'Гонконг долларӗ',
],
'HNL' => [
'HNL',
'Гондурас лемпирӗ',
],
'HRK' => [
'HRK',
'Хорвати куни',
],
'HTG' => [
'HTG',
'Гаити гурдӗ',
],
'HUF' => [
'HUF',
'Венгри форинчӗ',
],
'IDR' => [
'IDR',
'Индонези рупийӗ',
],
'ILS' => [
'₪',
'Ҫӗнӗ Израиль шекелӗ',
],
'INR' => [
'₹',
'Инди рупийӗ',
],
'IQD' => [
'IQD',
'Ирак динарӗ',
],
'IRR' => [
'IRR',
'Иран риалӗ',
],
'ISK' => [
'ISK',
'Исланди кронӗ',
],
'JMD' => [
'JMD',
'Ямайка долларӗ',
],
'JOD' => [
'JOD',
'Иордан динарӗ',
],
'JPY' => [
'JP¥',
'Япони иени',
],
'KES' => [
'KES',
'Кени шиллингӗ',
],
'KGS' => [
'KGS',
'Киргиз сомӗ',
],
'KHR' => [
'KHR',
'Камбоджа риелӗ',
],
'KMF' => [
'KMF',
'Комора франкӗ',
],
'KPW' => [
'KPW',
'КХДР вони',
],
'KRW' => [
'₩',
'Корей вони',
],
'KWD' => [
'KWD',
'Кувейт динарӗ',
],
'KYD' => [
'KYD',
'Кайман утравӗсен долларӗ',
],
'KZT' => [
'KZT',
'Казах тенгейӗ',
],
'LAK' => [
'LAK',
'Лаос кипӗ',
],
'LBP' => [
'LBP',
'Ливан фунчӗ',
],
'LKR' => [
'LKR',
'Шри-ланка рупийӗ',
],
'LRD' => [
'LRD',
'Либери долларӗ',
],
'LSL' => [
'LSL',
'Лесото лотийӗ',
],
'LYD' => [
'LYD',
'Ливи динарӗ',
],
'MAD' => [
'MAD',
'Марокко дирхамӗ',
],
'MDL' => [
'MDL',
'Молдова лайӗ',
],
'MGA' => [
'MGA',
'Малагаси ариарийӗ',
],
'MKD' => [
'MKD',
'Македони денарӗ',
],
'MMK' => [
'MMK',
'Мьянман кьятӗ',
],
'MNT' => [
'MNT',
'Монголи тугрикӗ',
],
'MOP' => [
'MOP',
'Макао патаки',
],
'MRU' => [
'MRU',
'Мавритани угийӗ',
],
'MUR' => [
'MUR',
'Маврики рупийӗ',
],
'MVR' => [
'MVR',
'Мальдивсен руфийӗ',
],
'MWK' => [
'MWK',
'Малави квачӗ',
],
'MXN' => [
'MX$',
'Мексика песийӗ',
],
'MYR' => [
'MYR',
'Малайзи ринггичӗ',
],
'MZN' => [
'MZN',
'Мозамбик метикалӗ',
],
'NAD' => [
'NAD',
'Намиби долларӗ',
],
'NGN' => [
'NGN',
'Нигери найрӗ',
],
'NIO' => [
'NIO',
'Никарагуа кордобӗ',
],
'NOK' => [
'NOK',
'Норвеги кронӗ',
],
'NPR' => [
'NPR',
'Непал рупийӗ',
],
'NZD' => [
'NZ$',
'Ҫӗнӗ Зеланди долларӗ',
],
'OMR' => [
'OMR',
'Оман риалӗ',
],
'PAB' => [
'PAB',
'Панама бальбоа',
],
'PEN' => [
'PEN',
'Перу солӗ',
],
'PGK' => [
'PGK',
'Папуа Ҫӗнӗ Гвиней кини',
],
'PHP' => [
'₱',
'Филиппин песийӗ',
],
'PKR' => [
'PKR',
'пакистан рупийӗ',
],
'PLN' => [
'PLN',
'Польша злотыйӗ',
],
'PYG' => [
'PYG',
'Парагвай гуаранӗ',
],
'QAR' => [
'QAR',
'Катар риалӗ',
],
'RON' => [
'RON',
'Румыни лейӗ',
],
'RSD' => [
'RSD',
'Серби динарӗ',
],
'RUB' => [
'₽',
'Раҫҫей тенкӗ',
],
'RWF' => [
'RWF',
'Руанда франкӗ',
],
'SAR' => [
'SAR',
'Сауд риялӗ',
],
'SBD' => [
'SBD',
'Соломон утравӗсен долларӗ',
],
'SCR' => [
'SCR',
'Сейшел рупийӗ',
],
'SDG' => [
'SDG',
'Судан фунчӗ',
],
'SEK' => [
'SEK',
'Швеци кронӗ',
],
'SGD' => [
'SGD',
'Сингапур долларӗ',
],
'SHP' => [
'SHP',
'Сӑваплӑ Елена утравӗн фунчӗ',
],
'SLE' => [
'SLE',
'леонӗ',
],
'SLL' => [
'SLL',
'леонӗ (1964—2022)',
],
'SOS' => [
'SOS',
'Сомали шиллингӗ',
],
'SRD' => [
'SRD',
'Суринам долларӗ',
],
'SSP' => [
'SSP',
'Кӑнтӑр Судан фунчӗ',
],
'STN' => [
'STN',
'Сан-Томе тата Принсипи добрӗ',
],
'SYP' => [
'SYP',
'Сири фунчӗ',
],
'SZL' => [
'SZL',
'Свази лилангенийӗ',
],
'THB' => [
'THB',
'Таиланд барӗ',
],
'TJS' => [
'TJS',
'Таджик сомонийӗ',
],
'TMT' => [
'TMT',
'Туркмен маначӗ',
],
'TND' => [
'TND',
'Тунези динарӗ',
],
'TOP' => [
'TOP',
'Тонган паанги',
],
'TRY' => [
'TRY',
'Турци лири',
],
'TTD' => [
'TTD',
'Тринидад тата Тобаго долларӗ',
],
'TWD' => [
'NT$',
'Ҫӗнӗ Тайван долларӗ',
],
'TZS' => [
'TZS',
'Танзани шиллингӗ',
],
'UAH' => [
'UAH',
'Украина гривни',
],
'UGX' => [
'UGX',
'Уганда шиллингӗ',
],
'USD' => [
'$',
'АПШ долларӗ',
],
'UYU' => [
'UYU',
'Уругвай песийӗ',
],
'UZS' => [
'UZS',
'Узбек сумӗ',
],
'VES' => [
'VES',
'Венесуэла боливарӗ',
],
'VND' => [
'₫',
'Вьетнам донгӗ',
],
'VUV' => [
'VUV',
'Вануату ватуйӗ',
],
'WST' => [
'WST',
'Самоа тали',
],
'XAF' => [
'FCFA',
'Тӗп Африка КФА франкӗ',
],
'XCD' => [
'EC$',
'Хӗвелтухӑҫ Карибсем долларӗ',
],
'XOF' => [
'FCFA',
'КФА ВСЕАО франкӗ',
],
'XPF' => [
'CFPF',
'Франци Лӑпкӑ океан франкӗ',
],
'YER' => [
'YER',
'Йемен риалӗ',
],
'ZAR' => [
'ZAR',
'Кӑнтӑр Африка рэндӗ',
],
'ZMW' => [
'ZMW',
'Замби квачи',
],
],
];

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,22 @@
<?php
return [
'Names' => [
'BYN' => [
'BYN',
'Weissrussischer Rubel',
],
'BYR' => [
'BYR',
'Weissrussischer Rubel (20002016)',
],
'EUR' => [
'EUR',
'Euro',
],
'STN' => [
'STN',
'São-toméischer Dobra (2018)',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'EUR' => [
'EUR',
'Euro',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'LUF' => [
'F',
'Luxemburgischer Franc',
],
],
];

View File

@@ -0,0 +1,306 @@
<?php
return [
'Names' => [
'AED' => [
'AED',
'ཡུ་ནཱའི་ཊེཌ་ ཨ་རབ་ ཨེ་མེ་རེཊས་ཀྱི་དངུལ་ ཌིར་ཧཱམ',
],
'AFN' => [
'AFN',
'ཨཕ་གཱན་གྱི་དངུལ་ ཨཕ་ག་ནི',
],
'AUD' => [
'AU$',
'ཨཱོས་ཊྲེ་ལི་ཡ་གི་དངུལ་ ཌོ་ལར',
],
'BDT' => [
'BDT',
'བྷང་ལ་དེཤ་གི་དངུལ་ ཏ་ཀ',
],
'BMD' => [
'BMD',
'བར་མུ་ཌ་གི་དངུལ་ ཌོ་ལར',
],
'BRL' => [
'R$',
'བྲ་ཛིལ་གྱི་དངུལ་ རེ་ཡལ',
],
'BTN' => [
'Nu.',
'དངུལ་ཀྲམ',
],
'CAD' => [
'CA$',
'ཀེ་ན་ཌ་གི་དངུལ་ ཌོ་ལར',
],
'CHF' => [
'CHF',
'སུ་ཡིས་ཀྱི་དངུལ་ ཕྲངཀ',
],
'CLP' => [
'CLP',
'ཅི་ལི་གི་དངུལ་ པེ་སོ',
],
'CNY' => [
'CN¥',
'རྒྱ་ནག་གི་དངུལ་ ཡུ་ཝཱན',
],
'COP' => [
'COP',
'ཀོ་ལོམ་བྷི་ཡ་གི་དངུལ་ པེ་སོ',
],
'CUP' => [
'CUP',
'ཀིའུ་བྷ་གི་དངུལ་ པེ་སོ',
],
'DKK' => [
'DKK',
'ཌེན་མཱཀ་གི་དངུལ་ ཀྲོན',
],
'DZD' => [
'DZD',
'ཨཱལ་ཇི་རི་ཡ་གི་དངུལ་ ཌའི་ནར',
],
'EGP' => [
'EGP',
'ཨི་ཇིབཊ་གི་དངུལ་ པ་འུནཌ',
],
'EUR' => [
'€',
'ཡུ་རོ༌དངུལ་',
],
'GBP' => [
'£',
'བྲི་ཊིཤ་ པ་འུནཌ་ ཨིས་ཊར་ལིང',
],
'HKD' => [
'HK$',
'ཧོང་ཀོང་གི་དངུལ་ ཌོ་ལར',
],
'IDR' => [
'IDR',
'ཨིན་ཌོ་ནེ་ཤི་ཡ་གི་དངུལ་ རུ་པི་ཡ',
],
'ILS' => [
'ILS',
'ཨིས་རེལ་གྱི་དངུལ་གསརཔ་ ཤེ་ཀེལ',
],
'INR' => [
'₹',
'རྒྱ་གར་གྱི་དངུལ་ རུ་པི',
],
'IQD' => [
'IQD',
'ཨི་རཱཀ་གི་དངུལ་ ཌི་ན',
],
'IRR' => [
'IRR',
'ཨི་རཱན་གྱི་དངུལ་ རི་ཨཱལ',
],
'ISK' => [
'ISK',
'ཨཱཡིས་ལེནཌ་གི་དངུལ་ ཀྲོ་ན',
],
'JMD' => [
'JMD',
'ཇཱ་མཻ་ཀ་གི་དངུལ་ ཌོ་ལར',
],
'JOD' => [
'JOD',
'ཇོར་ཌན་གྱི་དངུལ་ ཌི་ན',
],
'JPY' => [
'JP¥',
'ཇཱ་པཱན་གྱི་དངུལ་ ཡེན',
],
'KES' => [
'KES',
'ཀེན་ཡ་གི་དངུལ་ ཤི་ལིང',
],
'KHR' => [
'KHR',
'ཀེམ་བྷོ་ཌི་ཡ་གི་དངུལ་ རི་ཨཱལ',
],
'KPW' => [
'KPW',
'ནོརཐ་ ཀོ་རི་ཡ་གི་དངུལ་ ཝོན',
],
'KRW' => [
'KR₩',
'སཱའུཐ་ ཀོ་རི་ཡ་གི་དངུལ་ ཝོན',
],
'KWD' => [
'KWD',
'ཀུ་ཝེཊ་གི་དངུལ་ ཌི་ན',
],
'KZT' => [
'KZT',
'ཀ་ཛགས་ཏཱན་གྱི་དངུལ་ ཏེང་གེ',
],
'LAK' => [
'LAK',
'ལཱ་ཝོས་ཀྱི་དངུལ་ ཀིཔ',
],
'LBP' => [
'LBP',
'ལེ་བ་ནོན་གྱི་དངུལ་ པ་འུནཌ',
],
'LKR' => [
'LKR',
'ཤྲི་ ལང་ཀ་གི་དངུལ་ རུ་པི',
],
'LRD' => [
'LRD',
'ལཱའི་བེ་རི་ཡ་གི་དངུལ་ ཌོ་ལར',
],
'LYD' => [
'LYD',
'ལི་བི་ཡ་གི་དངུལ་ ཌི་ན',
],
'MAD' => [
'MAD',
'མོ་རོ་ཀོ་གི་དངུལ་ ཌིར་ཧཱམ',
],
'MMK' => [
'MMK',
'མི་ཡཱན་མར་གྱི་དངུལ་ ཅཱཏ',
],
'MNT' => [
'MNT',
'སོག་པོའི་དངུལ་ ཏུ་གྲིཀ',
],
'MVR' => [
'MVR',
'མཱལ་དིབས་ཀྱི་དངུལ་ རུ་ཕི་ཡ',
],
'MXN' => [
'MX$',
'མེཀ་སི་ཀོ་གི་དངུལ་ པེ་སོ',
],
'MYR' => [
'MYR',
'མ་ལེ་ཤི་ཡ་གི་དངུལ་ རིང་གིཊ',
],
'NOK' => [
'NOK',
'ནོར་ཝེ་གི་དངུལ་ ཀྲོ་ན',
],
'NPR' => [
'NPR',
'བལ་པོའི་དངུལ་ རུ་པི',
],
'NZD' => [
'NZ$',
'ནིའུ་ཛི་ལེནཌ་གི་དངུལ་ ཌོ་ལར',
],
'OMR' => [
'OMR',
'ཨོ་མཱན་གྱི་དངུལ་ རི་ཨཱལ',
],
'PAB' => [
'PAB',
'པ་ན་མ་གི་དངུལ་ བཱལ་བོ་ཝ',
],
'PEN' => [
'PEN',
'པ་རུ་གི་དངུལ་ ནུ་བོ་ སཱོལ',
],
'PHP' => [
'₱',
'ཕི་ལི་པིནས་གྱི་དངུལ་ པེ་སོ',
],
'PKR' => [
'PKR',
'པ་ཀིས་ཏཱན་གྱི་དངུལ་ རུ་པི',
],
'PLN' => [
'PLN',
'པོ་ལེནཌ་ཀྱི་དངུལ ཛ྄ལོ་ཊི',
],
'QAR' => [
'QAR',
'ཀ་ཊར་གྱི་དངུལ་ རི་ཨཱལ',
],
'RUB' => [
'RUB',
'ཨུ་རུ་སུ་གི་དངུལ་ རུ་བཱལ',
],
'SAR' => [
'SAR',
'སཱཝ་དིའི་དངུལ་ རི་ཡཱལ',
],
'SCR' => [
'SCR',
'སེ་ཤཱལས་ཀྱི་དངུལ་ རུ་པི',
],
'SEK' => [
'SEK',
'སུའི་ཌེན་གྱི་དངུལ་ ཀྲོ་ན',
],
'SGD' => [
'SGD',
'སིང་ག་པོར་གྱི་དངུལ་ ཌོ་ལར',
],
'SYP' => [
'SYP',
'སི་རི་ཡ་གི་དངུལ་ པ་འུནཌ',
],
'THB' => [
'TH฿',
'ཐཱའི་ལེནཌ་གི་དངུལ་ བཱཏ',
],
'TJS' => [
'TJS',
'ཏ་ཇི་ཀིས་ཏཱན་གྱི་དངུལ་ སོ་མོ་ནི',
],
'TRY' => [
'TRY',
'ཊཱར་ཀི་གི་དངུལ་ ལི་ར',
],
'TWD' => [
'NT$',
'ཊཱའི་ཝཱན་གི་དངུལ ཌོ་ལར',
],
'TZS' => [
'TZS',
'ཊཱན་ཛཱ་ནི་ཡ་གི་དངུལ་ ཤི་ལིང',
],
'UGX' => [
'UGX',
'ཡུ་གྷེན་ཌ་གི་དངུལ་ ཤི་ལིང',
],
'USD' => [
'US$',
'ཡུ་ཨེས་ ཌོ་ལར',
],
'UYU' => [
'UYU',
'ཡུ་རུ་གུ་ཝའི་གི་དངུལ་ པེ་སོ',
],
'UZS' => [
'UZS',
'ཨུས་བེ་ཀིས་ཏཱན་གྱི་དངུལ་ སོམ',
],
'VEF' => [
'VEF',
'བེ་ནི་ཛུ་ཝེ་ལ་གི་དངུལ་ བོ་ལི་བར (20082018)',
],
'VES' => [
'VES',
'བེ་ནི་ཛུ་ཝེ་ལ་གི་དངུལ་ བོ་ལི་བར',
],
'VND' => [
'₫',
'བེཊ་ནཱམ་གྱི་དངུལ་ ཌོང',
],
'XAF' => [
'XAF',
'XAF',
],
'ZAR' => [
'ZAR',
'སཱའུཐ་ ཨཕ་རི་ཀ་གི་དངུལ་ རཱནད',
],
],
];

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
<?php
return [
'Names' => [
'BMD' => [
'BMD',
'Bermudian Dollar',
],
'BYB' => [
'BYB',
'Belarusian New Rouble (19941999)',
],
'BYN' => [
'BYN',
'Belarusian Rouble',
],
'BYR' => [
'BYR',
'Belarusian Rouble (20002016)',
],
'JPY' => [
'JP¥',
'Japanese Yen',
],
'LVR' => [
'LVR',
'Latvian Rouble',
],
'RUB' => [
'RUB',
'Russian Rouble',
],
'RUR' => [
'RUR',
'Russian Rouble (19911998)',
],
'SHP' => [
'SHP',
'St Helena Pound',
],
'TJR' => [
'TJR',
'Tajikistani Rouble',
],
'USD' => [
'US$',
'US Dollar',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'EUR' => [
'€',
'Euro',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'XCD' => [
'$',
'East Caribbean Dollar',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'XCD' => [
'$',
'East Caribbean Dollar',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'EUR' => [
'€',
'Euro',
],
],
];

View File

@@ -0,0 +1,126 @@
<?php
return [
'Names' => [
'AUD' => [
'$',
'Australian Dollar',
],
'BAM' => [
'BAM',
'Bosnia-Herzegovina Convertible Marka',
],
'BBD' => [
'BBD',
'Barbados Dollar',
],
'BMD' => [
'BMD',
'Bermuda Dollar',
],
'BOB' => [
'BOB',
'Bolivian boliviano',
],
'BRL' => [
'BRL',
'Brazilian Real',
],
'CAD' => [
'CAD',
'Canadian Dollar',
],
'CNY' => [
'CNY',
'Chinese Yuan',
],
'EUR' => [
'EUR',
'Euro',
],
'GBP' => [
'GBP',
'British Pound',
],
'HKD' => [
'HKD',
'Hong Kong Dollar',
],
'ILS' => [
'ILS',
'Israeli Shekel',
],
'INR' => [
'INR',
'Indian Rupee',
],
'JPY' => [
'JPY',
'Japanese Yen',
],
'KRW' => [
'KRW',
'South Korean Won',
],
'MXN' => [
'MXN',
'Mexican Peso',
],
'NZD' => [
'NZD',
'New Zealand Dollar',
],
'PHP' => [
'PHP',
'Philippine Peso',
],
'SCR' => [
'Rs',
'Seychellois Rupee',
],
'SLL' => [
'SLL',
'Sierra Leonean Leone (19642022)',
],
'SRD' => [
'SRD',
'Suriname Dollar',
],
'TWD' => [
'TWD',
'New Taiwan Dollar',
],
'USD' => [
'USD',
'US Dollar',
],
'UYU' => [
'UYU',
'Peso Uruguayo',
],
'VES' => [
'VES',
'Venezuelan bolívar',
],
'VND' => [
'VND',
'Vietnamese Dong',
],
'XAF' => [
'XAF',
'Central African CFA Franc',
],
'XCD' => [
'XCD',
'East Caribbean Dollar',
],
'XOF' => [
'XOF',
'West African CFA Franc',
],
'XPF' => [
'CFP',
'CFP Franc',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'BBD' => [
'$',
'Barbadian Dollar',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'BIF' => [
'FBu',
'Burundian Franc',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'BMD' => [
'$',
'Bermudian Dollar',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'BSD' => [
'$',
'Bahamian Dollar',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'BWP' => [
'P',
'Botswanan Pula',
],
],
];

View File

@@ -0,0 +1,10 @@
<?php
return [
'Names' => [
'BZD' => [
'$',
'Belize Dollar',
],
],
];

Some files were not shown because too many files have changed in this diff Show More