-
-
Notifications
You must be signed in to change notification settings - Fork 9.8k
Description
At the moment, we have issues with regard to CLDR/ICU data (i.e. information about languages, currencies etc. that is collected by the CLDR project and exposed in a C API by the ICU project):
- Method calls are long:
Intl::getCurrencyBundle()->getCurrencyName(...) - We don't expose all information that is actually available in the CLDR data (e.g. see Flag deprecated currencies in the bundled ICU data, filter them out by default #11886)
- Since the bundles implement interfaces, we can't add methods to expose that data without breaking BC
To fix these problems, I suggest:
- Moving to static method calls for data access (e.g.
Currencies::getLocalizedName('EUR', 'en')). This has been discussed before in Use classes and interfaces to represent the shipped ICU data #11887.- The data is always available on the file system since we bundle it with the Intl component, hence I don't see a need to mock this information in tests and static access should be fine.
- Also, I don't see a need to provide value objects (
Currency), since we expose data only. Projects that need value objects need specialized value objects most of the time and are better off if they implement their own. We didn't find a good solution in Use classes and interfaces to represent the shipped ICU data #11887, so I suggest to KISS and move forward. - To avoid confusion with value object classes and to underline that the class contains static methods only, I suggest to use plural names.
- Adding new methods for accessing CLDR data that is currently not being exposed.
This work was started once in #9206, but abandoned. I suggest to look at the PR for inspiration.
To Do
- Migrate
CurrencyBundletoCurrencies - Migrate
LanguageBundletoLanguages - Migrate
LocaleBundletoLocales - Migrate
RegionBundletoCountries - Add
Scripts - Add
Timezones(started in [Intl] Provide translated timezone names #17636) - Analyze CLDR data and add accessors for available data
✨ Who wants to work on these PRs? ✨
Canonicalization
We should add canonicalize() methods to all static classes in order to canonicalize (normalize) language/currency/etc. codes. For example, fr-FR and fr_FR are both valid language codes. Within our code, we want to use one specific format, however (namely fr_FR). Language codes received from other sources (browsers, request headers, ...) can be passed to Languages::canonicalize() in order to convert them to Symfony's preferred format.
Currencies API
Here is a proposed API for the Currencies class. I added the doc comments from #9206 where needed for clarity. See #9206 for implementation inspiration.
class Currencies
{
/**
* Returns all available currencies.
*
* @return string[] An array of ISO 4217 three-letter currency codes
*/
public static function getCurrencyCodes();
public static function exists($currencyCode);
public static function canonicalize($currencyCode);
public static function getSymbol($currencyCode);
public static function getLocalizedName($currencyCode, $displayLocale = null);
public static function getLocalizedNames($displayLocale = null);
public static function getFractionDigits($currencyCode);
public static function getRoundingIncrement($currencyCode);
/**
* Returns the ISO 4217 numeric code of a currency.
*
* For example, the numeric code of the Canadian Dollar ("CAD") is 124. If
* no numeric code is available for a currency, 0 is returned.
*
* @param string $currency A canonical ISO 4217 three-letter currency code
* (e.g. "EUR")
*
* @return integer The numeric code
*
* @throws InvalidArgumentException If the currency code does not exist
*/
public static function getNumericCode($currencyCode);
/**
* Returns the matching ISO 4217 three-letter codes for a numeric code.
*
* For example, the numeric code 124 belongs to the Canadian Dollar ("CAD").
* Some numeric codes belong to multiple currencies. For example, the
* number 428 is assigned to both the Latvian Ruble ("LVR") and the Latvian
* Lats ("LVL"). For this reason, this method always returns an array.
*
* @param integer $numericCode An ISO 4217 numeric currency code (e.g. 124)
*
* @return string[] The matching ISO 4217 three-letter currency codes
*
* @throws InvalidArgumentException If the numeric code does not exist
*/
public static function forNumericCode($numericCode);
}Languages API
class Languages
{
/**
* Returns all available languages.
*
* 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 language codes
*/
public static function getLanguageCodes();
public static function exists($languageCode);
public static function canonicalize($languageCode);
public static function getLocalizedName($languageCode, $displayLocale = null);
public static function getLocalizedNames($displayLocale = null);
/**
* Returns the ISO 639-2 three-letter code of a language.
*
* @param string $language A canonical ISO 639 language code (e.g. "en")
*
* @return string The ISO 639-2 three-letter code of the language
*
* @throws InvalidArgumentException If the language is invalid
* @throws MissingResourceException If the language has no
* corresponding three-letter code
*/
public static function getAlpha3Code($languageCode)
}Locales API
class Locales
{
/**
* Returns all available locales.
*
* @return string[] A list of ICU locale codes
*/
public static function getLocales();
public static function exists($locale);
public static function canonicalize($locale);
public static function getLocalizedName($locale, $displayLocale = null);
public static function getLocalizedNames($displayLocale = null);
/**
* Returns a list of locale aliases.
*
* @return string[] An array with locale aliases as keys and ICU locale
* codes as values
*/
public static function getAliases();
/**
* Returns the fallback locale for a given locale, if any
*
* @param string $locale The ICU locale code to find the fallback for.
*
* @return string|null The ICU locale code of the fallback locale, or null
* if no fallback exists
*/
public static function getFallbackLocale($locale);
}Countries API
class Countries
{
public static function getCountryCodes();
public static function exists($countryCode);
public static function canonicalize($countryCode);
public static function getLocalizedName($countryCode, $displayLocale = null);
public static function getLocalizedNames($displayLocale = null);
public static function getAlpha3Code($countryCode);
public static function forAlpha3Code($alpha3Code);
}Scripts API
class Scripts
{
public static function getScriptCodes();
public static function exists($scriptCode);
public static function canonicalize($scriptCode);
public static function getLocalizedName($scriptCode, $displayLocale = null);
public static function getLocalizedNames($displayLocale = null);
}