Skip to content

Commit

Permalink
Fix #33: Add support for keywords hours, colnumeric, and `colcase…
Browse files Browse the repository at this point in the history
…first`

These keywords are part of the [ECMAScript 2022 Internationalization API Specification (ECMA-402 9th Edition)](https://tc39.es/ecma402/), and supporting them allows for better cross-communication between PHP and JavaScript layers. 
- `hours` defines an hour cycle for the locale (i.e. `h11`, `h12`, `h23`, `h24`). For more information see the [key/type definition for the Unicode Hour Cycle Identifier](https://www.unicode.org/reports/tr35/tr35-61/tr35.html#UnicodeHourCycleIdentifier). 
- `colnumeric` and `colcasefirst` are both collation settings defined as part of the [Unicode Locale Data Markup Language](https://www.unicode.org/reports/tr35/tr35-61/tr35-collation.html#Collation_Settings)
  • Loading branch information
ramsey committed Nov 5, 2021
1 parent 4c4c5d0 commit 6cc026a
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 3 deletions.
13 changes: 11 additions & 2 deletions CHANGELOG.md
@@ -1,9 +1,18 @@
# Yii i18n Change Log


## 1.0.1 under development
## 1.1.0 TBD

- New #33: Add support for keywords `hours`, `colnumeric`, and `colcasefirst`. These
keywords are part of the [ECMAScript 2022 Internationalization API Specification
(ECMA-402 9th Edition)](https://tc39.es/ecma402/), and supporting them allows
for better cross-communication between PHP and JavaScript layers.
- `hours` defines an hour cycle for the locale (i.e. `h11`, `h12`, `h23`, `h24`).
For more information see the [key/type definition for the Unicode Hour Cycle
Identifier](https://www.unicode.org/reports/tr35/tr35-61/tr35.html#UnicodeHourCycleIdentifier).
- `colnumeric` and `colcasefirst` are both collation settings defined as part
of the [Unicode Locale Data Markup Language](https://www.unicode.org/reports/tr35/tr35-61/tr35-collation.html#Collation_Settings) (ramsey)

- no changes in this release.

## 1.0.0 December 25, 2020

Expand Down
123 changes: 123 additions & 0 deletions src/Locale.php
Expand Up @@ -59,16 +59,39 @@ final class Locale
*/
private ?string $calendar = null;

/**
* @var string|null ICU case-first collation.
*
* @see https://unicode-org.github.io/icu/userguide/collation/customization/#casefirst
* @see https://www.unicode.org/reports/tr35/tr35-61/tr35-collation.html#Collation_Settings
*/
private ?string $colcasefirst = null;

/**
* @var string|null ICU collation.
*/
private ?string $collation = null;

/**
* @var string|null ICU numeric collation.
*
* @see https://unicode-org.github.io/icu/userguide/collation/customization/#numericordering
* @see https://www.unicode.org/reports/tr35/tr35-61/tr35-collation.html#Collation_Settings
*/
private ?string $colnumeric = null;

/**
* @var string|null ICU numbers.
*/
private ?string $numbers = null;

/**
* @var string|null Unicode hour cycle identifier.
*
* @see https://www.unicode.org/reports/tr35/#UnicodeHourCycleIdentifier
*/
private ?string $hours = null;

/**
* @var string|null
*/
Expand Down Expand Up @@ -134,17 +157,29 @@ public function __construct(string $localeString)
$this->calendar = $value;
}

if ($key === 'colcasefirst') {
$this->colcasefirst = $value;
}

if ($key === 'collation') {
$this->collation = $value;
}

if ($key === 'colnumeric') {
$this->colnumeric = $value;
}

if ($key === 'currency') {
$this->currency = $value;
}

if ($key === 'numbers') {
$this->numbers = $value;
}

if ($key === 'hours') {
$this->hours = $value;
}
}
}
}
Expand Down Expand Up @@ -237,6 +272,32 @@ public function withCalendar(?string $calendar): self
return $new;
}

/**
* @return string|null ICU case-first collation.
*
* @see https://unicode-org.github.io/icu/userguide/collation/customization/#casefirst
* @see https://www.unicode.org/reports/tr35/tr35-61/tr35-collation.html#Collation_Settings
*/
public function colcasefirst(): ?string
{
return $this->colcasefirst;
}

/**
* @param string|null $colcasefirst ICU case-first collation.
*
* @see https://unicode-org.github.io/icu/userguide/collation/customization/#casefirst
* @see https://www.unicode.org/reports/tr35/tr35-61/tr35-collation.html#Collation_Settings
*
* @return self
*/
public function withColcasefirst(?string $colcasefirst): self
{
$new = clone $this;
$new->colcasefirst = $colcasefirst;
return $new;
}

/**
* @return string|null ICU collation.
*/
Expand All @@ -257,6 +318,32 @@ public function withCollation(?string $collation): self
return $new;
}

/**
* @return string|null ICU numeric collation.
*
* @see https://unicode-org.github.io/icu/userguide/collation/customization/#numericordering
* @see https://www.unicode.org/reports/tr35/tr35-61/tr35-collation.html#Collation_Settings
*/
public function colnumeric(): ?string
{
return $this->colnumeric;
}

/**
* @param string|null $colnumeric ICU numeric collation.
*
* @see https://unicode-org.github.io/icu/userguide/collation/customization/#numericordering
* @see https://www.unicode.org/reports/tr35/tr35-61/tr35-collation.html#Collation_Settings
*
* @return self
*/
public function withColnumeric(?string $colnumeric): self
{
$new = clone $this;
$new->colnumeric = $colnumeric;
return $new;
}

/**
* @return string|null ICU numbers.
*/
Expand All @@ -277,6 +364,30 @@ public function withNumbers(?string $numbers): self
return $new;
}

/**
* @return string|null Unicode hour cycle identifier.
*
* @see https://www.unicode.org/reports/tr35/#UnicodeHourCycleIdentifier
*/
public function hours(): ?string
{
return $this->hours;
}

/**
* @param string|null $hours Unicode hour cycle identifier.
*
* @see https://www.unicode.org/reports/tr35/#UnicodeHourCycleIdentifier
*
* @return self
*/
public function withHours(?string $hours): self
{
$new = clone $this;
$new->hours = $hours;
return $new;
}

/**
* @return string Two-letter ISO 3166-1 country code.
*
Expand Down Expand Up @@ -434,15 +545,24 @@ public function asString(): string
if ($this->currency !== null) {
$keywords[] = 'currency=' . $this->currency;
}
if ($this->colcasefirst !== null) {
$keywords[] = 'colcasefirst=' . $this->colcasefirst;
}
if ($this->collation !== null) {
$keywords[] = 'collation=' . $this->collation;
}
if ($this->colnumeric !== null) {
$keywords[] = 'colnumeric=' . $this->colnumeric;
}
if ($this->calendar !== null) {
$keywords[] = 'calendar=' . $this->calendar;
}
if ($this->numbers !== null) {
$keywords[] = 'numbers=' . $this->numbers;
}
if ($this->hours !== null) {
$keywords[] = 'hours=' . $this->hours;
}

$string = implode('-', $result);

Expand All @@ -462,10 +582,13 @@ public function fallbackLocale(): self
{
$fallback = $this
->withCalendar(null)
->withColcasefirst(null)
->withCollation(null)
->withColnumeric(null)
->withCurrency(null)
->withExtendedLanguage(null)
->withNumbers(null)
->withHours(null)
->withPrivate(null);

if ($fallback->variant() !== null) {
Expand Down
52 changes: 51 additions & 1 deletion tests/LocaleTest.php
Expand Up @@ -72,18 +72,36 @@ public function testCalendarParsedCorrectly(): void
$this->assertSame('buddhist', $locale->calendar());
}

public function testColcasefirstParsedCorrectly(): void
{
$locale = new Locale('fr-Latn-FR@colcasefirst=upper');
$this->assertSame('upper', $locale->colcasefirst());
}

public function testCollationParsedCorrectly(): void
{
$locale = new Locale('es@collation=traditional');
$this->assertSame('traditional', $locale->collation());
}

public function testColnumericParsedCorrectly(): void
{
$locale = new Locale('fr-Latn-FR@colnumeric=yes');
$this->assertSame('yes', $locale->colnumeric());
}

public function testNumbersParsedCorrectly(): void
{
$locale = new Locale('ru-RU@numbers=latn');
$this->assertSame('latn', $locale->numbers());
}

public function testHoursParsedCorrectly(): void
{
$locale = new Locale('fr-FR@hours=h23');
$this->assertSame('h23', $locale->hours());
}

public function testCurrencyParsedCorrectly(): void
{
$locale = new Locale('ru-RU@currency=USD');
Expand All @@ -104,7 +122,9 @@ public function testPrivateIsParsedCorrectly(): void

public function testAsString(): void
{
$localeString = 'zh-cmn-Hans-CN-boont-r-extended-sequence-x-private@currency=USD;collation=traditional;calendar=buddhist;numbers=latn';
$localeString = 'zh-cmn-Hans-CN-boont-r-extended-sequence-x-private@'
. 'currency=USD;colcasefirst=lower;collation=traditional;colnumeric=no;'
. 'calendar=buddhist;numbers=latn;hours=h24';
$localeStringGrandFathered = 'zh-xiang';
$locale = new Locale($localeString);
$localeGrandFathered = new Locale($localeStringGrandFathered);
Expand Down Expand Up @@ -186,6 +206,26 @@ public function testWithNumbers(): void
$this->assertNotSame($locale, $newLocale);
}

public function testWithHours(): void
{
$locale = new Locale('fr');
$newLocale = $locale->withHours('h12');

$this->assertNull($locale->hours());
$this->assertSame('h12', $newLocale->hours());
$this->assertNotSame($locale, $newLocale);
}

public function testWithColcasefirst(): void
{
$locale = new Locale('fr');
$newLocale = $locale->withColcasefirst('false');

$this->assertNull($locale->colcasefirst());
$this->assertSame('false', $newLocale->colcasefirst());
$this->assertNotSame($locale, $newLocale);
}

public function testWithCollation(): void
{
$locale = new Locale('fr');
Expand All @@ -196,6 +236,16 @@ public function testWithCollation(): void
$this->assertNotSame($locale, $newLocale);
}

public function testWithColnumeric(): void
{
$locale = new Locale('fr');
$newLocale = $locale->withColnumeric('no');

$this->assertNull($locale->colnumeric());
$this->assertSame('no', $newLocale->colnumeric());
$this->assertNotSame($locale, $newLocale);
}

public function testWithVariant(): void
{
$locale = new Locale('de-DE');
Expand Down

0 comments on commit 6cc026a

Please sign in to comment.