Giter Site home page Giter Site logo

cldr's Introduction

CLDR

Packagist Downloads Code Quality

The CLDR package facilitates the internationalization of your application by leveraging the data and conventions established by the Unicode Common Locale Data Repository (CLDR). It provides valuable locale information such as names for territories, languages, days… as well as formatters for numbers, currencies, dates and times, units, sequences, and lists.

Note

The package targets CLDR version 45; Revision 72.

Example usage

<?php

use ICanBoogie\CLDR\Numbers\Currency;

/* @var ICanBoogie\CLDR\Repository $repository */

# You get a locale from the repository, here the locale for French.
$fr = $repository->locale_for('fr');

# You can use a locale instance as an array
echo $fr['characters']['auxiliary'];                // [á å ä ã ā ē í ì ī ñ ó ò ö ø ú ǔ]
echo $fr['delimiters']['quotationStart'];           // «
echo $fr['territories']['TF'];                      // Terres australes françaises

# You can localize it and get its local name
echo $fr->localized($fr)->name;                      // Français

# You can use it to format numbers, percents, currencies, lists…
echo $fr->format_number(12345.67);                  // 12 345,67
echo $fr->format_percent(.1234567);                 // 12 %
echo $fr->format_currency(12345.67, 'EUR');         // 12 345,67 €
echo $fr->format_list([ "Un", "deux", "trois" ]);   // Un, deux et trois

# You can get the default calendar for a locale and access its data
$calendar = $fr->calendar;
echo $calendar['days']['format']['wide']['sun'];    // dimanche
echo $calendar->wide_days['sun'];                   // dimanche

# You can use the calendar to format dates, times, or both
$datetime = '2018-11-24 20:12:22 UTC';
echo $calendar->format_date($datetime, 'long');     // 24 novembre 2018
echo $calendar->format_time($datetime, 'long');     // 20:12:22 UTC
echo $calendar->format_datetime($datetime, 'full'); // samedi 24 novembre 2018 à 20:12:22 UTC

# Alternatively, you can localize a DateTimeInterface and get formatted dates of various lengths
$datetime = new \DateTime('2013-11-04 20:21:22 UTC');
$fr_datetime = new \ICanBoogie\CLDR\Dates\LocalizedDateTime($datetime, $fr);
echo $fr_datetime->as_full;                         // lundi 4 novembre 2013 à 20:21:22 UTC
echo $fr_datetime->as_long;                         // 4 novembre 2013 à 20:21:22 UTC
echo $fr_datetime->as_medium;                       // 4 nov. 2013 20:21:22
echo $fr_datetime->as_short;                        // 04/11/2013 20:21

# You can format units
$units = $repository->locale_for('en')->units;
echo $units->duration_hour->name;                   // hours
echo $units->duration_hour->short_name;             // h
echo $units->duration_hour(1);                      // 1 hour
echo $units->duration_hour(23);                     // 23 hours
echo $units->duration_hour(23)->as_short;           // 23 hr
echo $units->duration_hour(23)->as_narrow;          // 23h

# You can format a unit per another unit
echo $units->volume_liter(12.345)->per($units->duration_hour);
// 12.345 liters per hour
echo $units->volume_liter(12.345)->per($units->duration_hour)->as_short;
// 12.345 L/h
echo $units->volume_liter(12.345)->per($units->duration_hour)->as_narrow;
// 12.345L/h

# You can format sequences of units
$units->sequence->angle_degree(5)->duration_minute(30)->as_narrow;
// 5° 30m
$units->sequence->length_foot(3)->length_inch(2)->as_short;
// 3 ft, 2 in

# You can access plural rules
$repository->plurals->rule_for(1.5, 'fr'); // one
$repository->plurals->rule_for(2, 'fr');   // other
$repository->plurals->rule_for(2, 'ar');   // two

# You can access currencies and their localized data
$euro = Currency::of('EUR');
$fr_euro = $euro->localized($fr);
echo $fr_euro->name;
echo $fr_euro->name_for(1);      // euro
echo $fr_euro->name_for(10);     // euros
echo $fr_euro->format(12345.67); // 12 345,67 €

# You can access territories and their localized data
$territory = $repository->territory_for('FR');
echo $territory;                                       // FR
echo $territory->currency;                             // EUR
echo $territory->currency_at('1977-06-06');            // FRF
echo $territory->currency_at('now');                   // EUR
echo $territory->name_as('fr');        // France
echo $territory->name_as('it');        // Francia
echo $territory->name_as('ja');        // フランス
echo $repository->territory_for('FR')->first_day;        // mon
echo $repository->territory_for('EG')->first_day;        // sat
echo $repository->territory_for('BS')->first_day;        // sun
echo $repository->territory_for('AE')->weekend_start;    // fri
echo $repository->territory_for('AE')->weekend_end;      // sat
echo $territory->localized('fr')->name; // France
echo $territory->localized('it')->name; // Francia
echo $territory->localized('ja')->name; // フランス

Installation

composer require icanboogie/cldr

Documentation

The documentation is divided into the following parts, mimicking Unicode's documentation:

  • Part 1: Core (languages, locales, basic structure)
  • Part 2: General (display names & transforms, etc.)
  • Part 3: Numbers (number & currency formatting)
  • Part 4: Dates (date, time, time zone formatting)
  • Part 5: Collation (sorting, searching, grouping)
  • Part 6: Supplemental (supplemental data)

Getting started

The CLDR is represented by a Repository instance, which accesses data through a Provider instance. The package offers several and caching mechanisms. Choosing the right provider depends on your requirements: you may prioritize flexibility during development or predictability in production.

Favor flexibility

WebProvider offers maximum flexibility by retrieving data from the JSON distribution hosted on GitHub as needed. To minimize web requests, it is advised to use a collection of caches, each with its own strategy. For example, FileCache stores the retrieved data as PHP files, allowing it to benefit from opcache.

The following example demonstrates how a repository can be instantiated:

<?php

use ICanBoogie\CLDR\Cache\CacheCollection;
use ICanBoogie\CLDR\Cache\FileCache;
use ICanBoogie\CLDR\Cache\RedisCache;
use ICanBoogie\CLDR\Cache\RuntimeCache;
use ICanBoogie\CLDR\Provider\CachedProvider;
use ICanBoogie\CLDR\Provider\WebProvider;
use ICanBoogie\CLDR\Repository;

/* @var \Redis $redis_client */

$provider = new CachedProvider(
    new WebProvider,
    new CacheCollection([
        new RunTimeCache,
        // You don't have to use Redis, this is only an example
        new RedisCache($redis_client),
        new FileCache(FileCache::RECOMMENDED_DIR)
    ])
);

$cldr = new Repository($provider);

Favor predictability

For greater predictability, consider limiting the repository's usage to a few specific locales and distributing them as part of your application. You can prepopulate the CLDR cache during development and commit the files, or incorporate this step into your CI/CD pipeline build process.

Use the cldr command to warm up the CLDR cache:

./vendor/bin/cldr warm-up de en fr

The following example illustrates a setup to limit data access to the cache. RestrictedProvider throws an exception in an attempt to retrieve data not available in the cache.

<?php

use ICanBoogie\CLDR\Cache\FileCache;
use ICanBoogie\CLDR\Provider\CachedProvider;
use ICanBoogie\CLDR\Provider\RestrictedProvider;
use ICanBoogie\CLDR\Repository;

$provider = new CachedProvider(
    new RestrictedProvider(),
    new FileCache(FileCache::RECOMMENDED_DIR),
);

$cldr = new Repository($provider);

Continuous Integration

The project is continuously tested by GitHub actions.

Tests Code Coverage Static Analysis Code Style

Code of Conduct

This project adheres to a Contributor Code of Conduct. By participating in this project and its community, you're expected to uphold this code.

Contributing

See CONTRIBUTING for details.

License

icanboogie/cldr is released under the MIT License.

cldr's People

Contributors

kornrunner avatar olvlvl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

cldr's Issues

Locale with empty identifier

Creating a Locale instance with an empty identifier shouldn't be possible:

<?php

use ICanBoogie\CLDR\Locale;

$locale = new Locale($repository, "");

Add formatting methods to calendar

<?php

/* @var ICanBoogie\CLDR\Calendar $calendar */

echo $calendar->datetime_formatter->format($datetime, 'long');
echo $calendar->date_formatter->format($datetime, 'long');
echo $calendar->time_formatter->format($datetime, 'long');

// or

echo $calendar->format_datetime($datetime, 'long');
echo $calendar->format_date($datetime, 'long');
echo $calendar->format_time($datetime, 'long');

Reorganize namespace

Reorganize namespace according to dependencies:

  • Numbers depends on Locale -> ICanBoogie\CLDR\Locale
  • DateTimeFormat depends on Calendar -> ICanBoogie\CLDR\Calendar

Everything that depends on the Repository should stay in the root. For everything else, move to the context.

Optimizations

  1. LocalizedCurrency::lazy_get_formatter()

    protected function lazy_get_formatter()
    {
    	return new LocalizedCurrencyFormatter(new CurrencyFormatter($this->locale->repository), $this->locale);
    }
    protected function lazy_get_formatter()
    {
    	return $this->locale->currency_formatter;
    }
  2. Use AbstractCollection whenever possible

    • CurrencyCollection
    • TerritoryCollection

Unicode mapping fallback

Hello everyone,
I'm posting here for an issue I'm having with this library and PrestaShop v1.7+

Apparently the Prestashop devs have included your library in the installation process and many users are experiencing some problem with the provide function. Apparently, under certain conditions, the codeMappings.json file can't be downloaded, thus the installation fails.

A workaround for this issue appears to be to provide the codeMappings.json file separately, I've personally fixed my issue by changing the function to this:

/**
     * The section path, following the pattern "<identity>/<section>".
     *
     * @param string $path
     *
     * @throws ResourceNotFound when the specified path does not exists on the CLDR source.
     *
     * @return string
     */
    public function provide($path)
    {
        #$connection = $this->obtain_connection();

        #curl_setopt($connection, CURLOPT_URL, $this->origin . $path . '.json');

        #$rc = curl_exec($connection);

        #$http_code = curl_getinfo($connection, CURLINFO_HTTP_CODE);

        #if ($http_code != 200)
        #{
        #   throw new ResourceNotFound($path);
        #}
        #
        $rc = file_get_contents('/app/vendor/icanboogie/cldr/lib/codeMappings.json');

        return json_decode($rc, true);
    }

I'm now providing the file here, just in case you can't reach unicode.org.

It will be nice if the file gets included directly in this repo

The error in PrestaShop is the following:
screenshot from 2017-08-29 00-05-45

1: HTTP 200 - parsererror -
Fatal error: Uncaught ICanBoogie\CLDR\ResourceNotFound: Path not defined: supplemental/codeMappings. in /app/vendor/icanboogie/cldr/lib/WebProvider.php:77 Stack trace: #0 /app/vendor/icanboogie/cldr/lib/ProviderChainTrait.php(43): ICanBoogie\CLDR\WebProvider->provide('supplemental/co...') #1 /app/vendor/icanboogie/cldr/lib/ProviderChainTrait.php(43): ICanBoogie\CLDR\FileProvider->provide('supplemental/co...') #2 /app/vendor/icanboogie/cldr/lib/Repository.php(124): ICanBoogie\CLDR\RunTimeProvider->provide('supplemental/co...') #3 /app/vendor/icanboogie/cldr/lib/Supplemental.php(95): ICanBoogie\CLDR\Repository->fetch('supplemental/co...') #4 /app/src/Core/Cldr/Repository.php(301): ICanBoogie\CLDR\Supplemental->offsetGet('codeMappings') #5 /app/src/Core/Cldr/Repository.php(226): PrestaShop\PrestaShop\Core\Cldr\Repository->isCurrencyValid('CHF') #6 /app/classes/Currency.php(135): PrestaShop\PrestaShop\Core\Cldr\Repository->getCurrency('CHF') #7 /app/classes/LocalizationPack.php(326): CurrencyCore->add() #8 /app/classes/Locali in /app/vendor/icanboogie/cldr/lib/WebProvider.php on line 77

Remove all providers but WebProvider

All providers but WebProvider should be removed. Other providers, that are actually cache layers, should be removed, as well as the ProviderCollection class. A cache collection can simply implement the Provider interface, and it's last cache can use WebProvider to fetch its data.

Exception regarding missing "contextTransformations" in some locales

Hi,

I'm running the following code:

<?php
require 'vendor/autoload.php';

use ICanBoogie\CLDR\Repository;
use ICanBoogie\CLDR\Cache\CacheCollection;
use ICanBoogie\CLDR\Cache\RuntimeCache;
use ICanBoogie\CLDR\Provider\CachedProvider;
use ICanBoogie\CLDR\Provider\WebProvider;

$provider = new CachedProvider(
    new WebProvider,
    new CacheCollection([
        new RunTimeCache,
    ])
);

$repository = new Repository($provider);

$locale = $repository->locales['zh'];
$calendar = $locale->calendar;

And I am getting the following Exception:

Fatal error: Uncaught ICanBoogie\CLDR\ResourceNotFound: Path not defined: main/zh/contextTransforms. in /tmp/cldr/vendor/icanboogie/cldr/lib/Provider/WebProvider.php on line 64

ICanBoogie\CLDR\ResourceNotFound: Path not defined: main/zh/contextTransforms. in /tmp/cldr/vendor/icanboogie/cldr/lib/Provider/WebProvider.php on line 64

Call Stack:
    0.0003     384848   1. {main}() /tmp/cldr/bug-test.php:0
    0.2613     620984   2. ICanBoogie\CLDR\AbstractSectionCollection->__get($property = 'calendar') /tmp/cldr/bug-test.php:20
    0.2613     620984   3. ICanBoogie\CLDR\AbstractSectionCollection->accessor_get($property = 'calendar') /tmp/cldr/vendor/icanboogie/accessor/lib/AccessorTrait.php:38
    0.2613     621064   4. ICanBoogie\CLDR\Locale->lazy_get_calendar() /tmp/cldr/vendor/icanboogie/accessor/lib/AccessorTrait.php:110
    0.2617     624472   5. ICanBoogie\CLDR\AbstractCollection->offsetGet($id = 'gregorian') /tmp/cldr/vendor/icanboogie/cldr/lib/Locale.php:116
    0.2617     624472   6. ICanBoogie\CLDR\CalendarCollection->ICanBoogie\CLDR\{closure:/tmp/cldr/vendor/icanboogie/cldr/lib/CalendarCollection.php:40-44}($id = 'gregorian') /tmp/cldr/vendor/icanboogie/cldr/lib/AbstractCollection.php:61
    0.5010     732776   7. ICanBoogie\CLDR\Calendar->__construct($locale = class ICanBoogie\CLDR\Locale { protected $sections = []; private ${ICanBoogie\CLDR\AbstractSectionCollection}name = 'main/zh'; private ${ICanBoogie\CLDR\AbstractSectionCollection}repository = class ICanBoogie\CLDR\Repository { private $provider = class ICanBoogie\CLDR\Provider\CachedProvider { ... }; public $locales = class ICanBoogie\CLDR\LocaleCollection { ... }; public $available_locales = [...] }; private $code = 'zh'; private ${ICanBoogie\CLDR\AbstractSectionCollection}available_sections = ['ca-buddhist' => 'dates/calendars/buddhist', 'ca-chinese' => 'dates/calendars/chinese', 'ca-coptic' => 'dates/calendars/coptic', 'ca-dangi' => 'dates/calendars/dangi', 'ca-ethiopic' => 'dates/calendars/ethiopic', 'ca-generic' => 'dates/calendars/generic', 'ca-gregorian' => 'dates/calendars/gregorian', 'ca-hebrew' => 'dates/calendars/hebrew', 'ca-indian' => 'dates/calendars/indian', 'ca-islamic' => 'dates/calendars/islamic', 'ca-japanese' => 'dates/calendars/japanese', 'ca-persian' => 'dates/calendars/persian', 'ca-roc' => 'dates/calendars/roc', 'characters' => 'characters', 'contextTransforms' => 'contextTransforms', 'currencies' => 'numbers/currencies', 'dateFields' => 'dates/fields', 'delimiters' => 'delimiters', 'languages' => 'localeDisplayNames/languages', 'layout' => 'layout', 'listPatterns' => 'listPatterns', 'localeDisplayNames' => 'localeDisplayNames', 'measurementSystemNames' => 'localeDisplayNames/measurementSystemNames', 'numbers' => 'numbers', 'posix' => 'posix', 'scripts' => 'localeDisplayNames/scripts', 'territories' => 'localeDisplayNames/territories', 'timeZoneNames' => 'dates/timeZoneNames', 'units' => 'units', 'variants' => 'localeDisplayNames/variants']; private ${ICanBoogie\CLDR\AbstractSectionCollection}sections = ['ca-gregorian' => [...]]; public $calendars = class ICanBoogie\CLDR\CalendarCollection { private ${ICanBoogie\CLDR\AbstractCollection}collection = [...]; private ${ICanBoogie\CLDR\AbstractCollection}create_instance = class Closure { virtual $closure = "$this->ICanBoogie\CLDR\{closure}", ... }; private $locale = ... } }, $data = ['months' => ['format' => [...], 'stand-alone' => [...]], 'days' => ['format' => [...], 'stand-alone' => [...]], 'quarters' => ['format' => [...], 'stand-alone' => [...]], 'dayPeriods' => ['format' => [...], 'stand-alone' => [...]], 'eras' => ['eraNames' => [...], 'eraAbbr' => [...], 'eraNarrow' => [...]], 'dateFormats' => ['full' => 'y年M月d日EEEE', 'long' => 'y年M月d日', 'medium' => 'y年M月d日', 'short' => 'y/M/d'], 'timeFormats' => ['full' => 'zzzz ah:mm:ss', 'long' => 'z ah:mm:ss', 'medium' => 'ah:mm:ss', 'short' => 'ah:mm'], 'dateTimeFormats' => ['full' => '{1} {0}', 'long' => '{1} {0}', 'medium' => '{1} {0}', 'short' => '{1} {0}', 'availableFormats' => [...], 'appendItems' => [...], 'intervalFormats' => [...]]]) /tmp/cldr/vendor/icanboogie/cldr/lib/CalendarCollection.php:42
    0.5010     732816   8. ICanBoogie\CLDR\AbstractSectionCollection->__get($property = 'context_transforms') /tmp/cldr/vendor/icanboogie/cldr/lib/Calendar.php:126
    0.5010     732816   9. ICanBoogie\CLDR\AbstractSectionCollection->accessor_get($property = 'context_transforms') /tmp/cldr/vendor/icanboogie/accessor/lib/AccessorTrait.php:38
    0.5010     732912  10. ICanBoogie\CLDR\Locale->lazy_get_context_transforms() /tmp/cldr/vendor/icanboogie/accessor/lib/AccessorTrait.php:110
    0.5015     733136  11. ICanBoogie\CLDR\AbstractSectionCollection->offsetGet($offset = 'contextTransforms') /tmp/cldr/vendor/icanboogie/cldr/lib/Locale.php:156
    0.5015     733232  12. ICanBoogie\CLDR\Repository->fetch($path = 'main/zh/contextTransforms') /tmp/cldr/vendor/icanboogie/cldr/lib/AbstractSectionCollection.php:82
    0.5015     733232  13. ICanBoogie\CLDR\Provider\CachedProvider->provide($path = 'main/zh/contextTransforms') /tmp/cldr/vendor/icanboogie/cldr/lib/Repository.php:153
    0.5016     733232  14. ICanBoogie\CLDR\Provider\WebProvider->provide($key = 'main/zh/contextTransforms') /tmp/cldr/vendor/icanboogie/cldr/lib/Provider/CachedProvider.php:50

I get this exception only of the 'contextTransformations' element isn't part of the XML file (in this case, https://github.com/unicode-org/cldr/blob/main/common/main/zh.xml). Even if the contextTransformations element is present, but has nothing for date times (like https://github.com/unicode-org/cldr/blob/main/common/main/vi.xml), it works.

NoRelation

We could instantiate a NoRelation when $x_expression evaluates to null, so we could remove conditions check for $x_expression === null in Relation.

Rename LocalizedCurrency::get_name() as name_for()

Because the prefix get_ is used in ICanBoogie to define getters and because get_name() indeed sounds like a getter, it should be renamed as name_for():

<?php

$currency->name;         // livre irlandaise
$currency->name_for(1);  // livre irlandaise
$currency->name_for(10); // livre irlandaises

CLDR targets v36 while latest version is 41

As of v4.0, ICanBoogie/CLDR targets CLDR v36 while v41 is available. A major change was introduced by v40, the packages are no longer split into multiple repositories, they are all part of one repository.

Proposed solution

  • Update PathMapper to target the new package layout.
  • Fix possible broken references.

Acceptance criteria

  • ICanBoogie/CLDR targets v41.
  • Support new plural operand e and compact decimal exponent (as in 123c6) — v36 vs v41
  • References to CLDR v36 are updated to v41.
  • Tests are passing.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.