PHP code example of matecat / icu-intl

1. Go to this page and download the library: Download matecat/icu-intl library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

matecat / icu-intl example snippets


use Matecat\ICU\MessagePattern;
use Matecat\ICU\Tokens\TokenType;

$patternText = "You have {num, plural, offset:1 =0{no messages} =1{one message} other{# messages}} in {folder}.";
$pattern = new MessagePattern($patternText);

// Get AST and traverse (Token is a small DTO with type, start, length, value, limit)
$indent = '';
foreach ($pattern as $i => $part) {
    $explanation = '';

    $partString = (string)$part;
    $type = $part->getType();

    if ($type === TokenType::MSG_START) {
        $indent = str_pad('', $part->getValue() * 4, ' ', STR_PAD_LEFT);
    }

    if ($part->getLength() > 0) {
        $explanation .= '="' . $pattern->parts()->getSubstring($part) . '"';
    }

    if ($type->hasNumericValue()) {
        $explanation .= '=' . $pattern->parts()->getNumericValue($part);
    }

    printf("%2d: %s%s%s\n", $i, $indent, $partString, $explanation);

    if ($type === TokenType::MSG_LIMIT) {
        $nestingLevel = $part->getValue();
        if ($nestingLevel > 1) {
            $indent = str_pad('', ($nestingLevel - 1) * 4, ' ', STR_PAD_LEFT);
        } else {
            $indent = '';
        }
    }
}

/*
     0: MSG_START(0)@0
     1: ARG_START(PLURAL)@9="{"
     2: ARG_NAME(0)@10="num"
     3: ARG_INT(1)@30="1"=1
     4: ARG_SELECTOR(0)@32="=0"
     5: ARG_INT(0)@33="0"=0
     6:     MSG_START(1)@34="{"
     7:     MSG_LIMIT(1)@46="}"
     8: ARG_SELECTOR(0)@48="=1"
     9: ARG_INT(1)@49="1"=1
    10:     MSG_START(1)@50="{"
    11:     MSG_LIMIT(1)@62="}"
    12: ARG_SELECTOR(0)@64="other"
    13:     MSG_START(1)@69="{"
    14:     REPLACE_NUMBER(0)@70="#"
    15:     MSG_LIMIT(1)@80="}"
    16: ARG_LIMIT(PLURAL)@81="}"
    17: ARG_START(NONE)@86="{"
    18: ARG_NAME(0)@87="folder"
    19: ARG_LIMIT(NONE)@93="}"
    20: MSG_LIMIT(0)@95
 */

$pattern = new MessagePattern("Hello {name}, welcome!");
/*
     0: MSG_START(0)@0
     1: ARG_START(NONE)@6="{"
     2: ARG_NAME(0)@7="name"
     3: ARG_LIMIT(NONE)@11="}"
     4: MSG_LIMIT(0)@22
*/

$pattern = new MessagePattern();
$pattern->parse("You have {count, plural, =0{no messages} one{# message} other{# messages}}.");

$pattern = MessagePattern::parse("{gender, select, female{{num, plural, one{She has one file} other{She has # files}}} male{{num, plural, one{He has one file} other{He has # files}}} other{{num, plural, one{They have one file} other{They have # files}}}}");
/*
     0: MSG_START(0)@0
     1: ARG_START(SELECT)@0="{"
     2: ARG_NAME(0)@1="gender"
     3: ARG_SELECTOR(0)@17="female"
     4:     MSG_START(1)@23="{"
     5:     ARG_START(PLURAL)@24="{"
     ...
    42: ARG_LIMIT(SELECT)@219="}"
    43: MSG_LIMIT(0)@220
 */

use Matecat\Locales\Languages;

// Get all supported languages
$languages = Languages::getInstance();
$allLanguages = $languages->getLanguages();

// Get a specific language by RFC3066 code
$english = $languages->getLanguage('en-US');
echo $english['name'];        // "English US"
echo $english['localized'];   // "English"
echo $english['direction'];   // "ltr"
echo $english['plurals'];     // 2

// Check if a language is RTL
$isRtl = $languages->isRTL('ar-SA'); // true

// Get the number of plural forms for a language
$pluralCount = Languages::getPluralsCount('ru-RU'); // 3

use Matecat\ICU\Plurals\PluralRules;

// Get the plural form index for a number in a specific language
$form = PluralRules::getCardinalFormIndex('en', 1);    // 0 (singular)
$form = PluralRules::getCardinalFormIndex('en', 5);    // 1 (plural)

$form = PluralRules::getCardinalFormIndex('ru', 1);    // 0 (one)
$form = PluralRules::getCardinalFormIndex('ru', 2);    // 1 (few)
$form = PluralRules::getCardinalFormIndex('ru', 5);    // 2 (many)

// Get the CLDR plural category name for a number
$category = PluralRules::getCardinalCategoryName('en', 1);    // "one"
$category = PluralRules::getCardinalCategoryName('en', 5);    // "other"

$category = PluralRules::getCardinalCategoryName('ru', 1);    // "one"
$category = PluralRules::getCardinalCategoryName('ru', 2);    // "few"
$category = PluralRules::getCardinalCategoryName('ru', 5);    // "many"

$category = PluralRules::getCardinalCategoryName('ar', 0);    // "zero"
$category = PluralRules::getCardinalCategoryName('ar', 1);    // "one"
$category = PluralRules::getCardinalCategoryName('ar', 2);    // "two"
$category = PluralRules::getCardinalCategoryName('ar', 5);    // "few"
$category = PluralRules::getCardinalCategoryName('ar', 11);   // "many"
$category = PluralRules::getCardinalCategoryName('ar', 100);  // "other"

// Get all available plural categories for a language
$categories = PluralRules::getCardinalCategories('en');  // ["one", "other"]
$categories = PluralRules::getCardinalCategories('ru');  // ["one", "few", "many"]
$categories = PluralRules::getCardinalCategories('ar');  // ["zero", "one", "two", "few", "many", "other"]

// Use category constants for comparison
if (PluralRules::getCardinalCategoryName('en', $count) === PluralRules::CATEGORY_ONE) {
    echo "Singular form";
}

use Matecat\ICU\MessagePatternValidator;
use Matecat\ICU\Plurals\PluralComplianceException;

// Simplified API: just provide locale and pattern string
$validator = new MessagePatternValidator('en', '{count, plural, one{# item} other{# items}}');
$warning = $validator->validatePluralCompliance();

// Returns null when all categories are valid and complete
var_dump($warning); // null - 'one' and 'other' are valid for English

// Fluent API with setPatternString()
$warning = (new MessagePatternValidator('ru'))
    ->setPatternString('{count, plural, one{# item} other{# items}}')
    ->validatePluralCompliance();

// Returns a PluralComplianceWarning - Russian  new MessagePatternValidator('en', '{count, plural, one{# item} other{# items}}');
$validator->isValidSyntax(); // true

$validator = new MessagePatternValidator('en', '{invalid');
$validator->isValidSyntax(); // false
$validator->getSyntaxException(); // "Unmatched '{' braces in message..."

use Matecat\ICU\MessagePattern;
use Matecat\ICU\MessagePatternValidator;

// Parse an ICU message first
$pattern = new MessagePattern();
$pattern->parse('{count, plural, one{# item} other{# items}}');

// Create validator using factory method
$validator = MessagePatternValidator::fromPattern('en', $pattern);
$warning = $validator->validatePluralCompliance();

// Validate same pattern against multiple locales (reuses the parsed pattern)
$enValidator = MessagePatternValidator::fromPattern('en', $pattern);
$ruValidator = MessagePatternValidator::fromPattern('ru', $pattern);
$arValidator = MessagePatternValidator::fromPattern('ar', $pattern);

$enValidator->validatePluralCompliance(); // null - English only needs 'one', 'other'
$ruValidator->validatePluralCompliance(); // warning - Russian needs 'one', 'few', 'many', 'other'

use Matecat\ICU\MessagePatternValidator;

// Access per-argument warnings
$validator = new MessagePatternValidator('ru', '{count, plural, one{# item} other{# items}}');
$warning = $validator->validatePluralCompliance();

foreach ($warning->getArgumentWarnings() as $argWarning) {
    echo $argWarning->argumentName;           // 'count'
    echo $argWarning->getArgumentTypeLabel(); // 'plural' or 'selectordinal'
    print_r($argWarning->expectedCategories); // ['one', 'few', 'many', 'other']
    print_r($argWarning->missingCategories);  // ['few', 'many']
    print_r($argWarning->foundSelectors);     // ['one', 'other']
    echo $argWarning->getMessageAsString();   // Detailed message for this argument
}

use Matecat\ICU\MessagePatternValidator;
use Matecat\ICU\Plurals\PluralComplianceException;

// Invalid CLDR categories throw an exception
$validator = new MessagePatternValidator('en', '{count, plural, some{# items} other{# items}}');

try {
    $validator->validatePluralCompliance();
} catch (PluralComplianceException $e) {
    echo $e->getMessage();
    // "Invalid selectors found for locale 'en': [some]. Found selectors: [some, other]. Valid CLDR categories are: [zero, one, two, few, many, other]."
    echo $e->locale;                  // 'en'
    print_r($e->invalidSelectors);    // ['some']
    print_r($e->foundSelectors);      // ['some', 'other']
    print_r($e->expectedCategories);  // ['zero', 'one', 'two', 'few', 'many', 'other']
}

use Matecat\ICU\MessagePatternValidator;

// Valid CLDR categories wrong for locale return warnings (not exceptions)
$validator = new MessagePatternValidator('en', '{count, plural, one{# item} few{# items} other{# items}}');
$warning = $validator->validatePluralCompliance();

$argWarning = $warning->getArgumentWarnings()[0];
print_r($argWarning->wrongLocaleSelectors); // ['few'] - valid CLDR but not for English

// Explicit numeric selectors (=0, =1, =2) are always valid but don't substitute category keywords
$validator = new MessagePatternValidator('en', '{count, plural, =0{none} =1{one item} other{# items}}');
$warning = $validator->validatePluralCompliance();

$argWarning = $warning->getArgumentWarnings()[0];
print_r($argWarning->numericSelectors);    // ['=0', '=1']
print_r($argWarning->missingCategories);   // ['one'] - =1 doesn't substitute for 'one' keyword

// Nested messages with multiple plural arguments get per-argument validation
$validator = new MessagePatternValidator(
    'en',
    "{gender, select, female{{n, plural, one{her item} other{her items}}} male{{n, plural, one{his item} other{his items}}}}"
);
$warning = $validator->validatePluralCompliance(); // null - all valid

// SelectOrdinal validation uses ordinal rules (different from cardinal)
$validator = new MessagePatternValidator('en', '{rank, selectordinal, one{#st} two{#nd} few{#rd} other{#th}}');
$warning = $validator->validatePluralCompliance(); // null - English ordinal uses one/two/few/other

use Matecat\ICU\MessagePatternComparator;
use Matecat\ICU\Exceptions\MissingComplexFormException;

// Compare source and target patterns
$comparator = new MessagePatternComparator(
    'en-US',                                                    // source locale
    'fr-FR',                                                    // target locale
    '{count, plural, one{# item} other{# items}}',              // source pattern
    '{count, plural, one{# article} many{# articles} other{# articles}}'  // target pattern
);

// Validate - throws exception if target is missing complex forms from source
$comparator->validate();

// Optionally validate plural compliance against CLDR rules for source, target, or both
$result = $comparator->validate(validateSource: true, validateTarget: true);

// $result->sourceWarnings — PluralComplianceWarning|null for the source pattern
// $result->targetWarnings — PluralComplianceWarning|null for the target pattern
if ($result->targetWarnings !== null) {
    echo $result->targetWarnings->getMessagesAsString();
}

use Matecat\ICU\MessagePattern;
use Matecat\ICU\MessagePatternComparator;
use Matecat\ICU\MessagePatternValidator;

// From pre-configured validators
$sourceValidator = new MessagePatternValidator('en', '{count, plural, one{# item} other{# items}}');
$targetValidator = new MessagePatternValidator('fr', '{count, plural, one{# article} other{# articles}}');
$comparator = MessagePatternComparator::fromValidators($sourceValidator, $targetValidator);

// From pre-parsed patterns (useful for comparing same patterns against multiple locale pairs)
$sourcePattern = new MessagePattern('{count, plural, one{# item} other{# items}}');
$targetPattern = new MessagePattern('{count, plural, one{# article} other{# articles}}');
$comparator = MessagePatternComparator::fromPatterns('en', 'fr', $sourcePattern, $targetPattern);

use Matecat\ICU\MessagePatternComparator;
use Matecat\ICU\Exceptions\MissingComplexFormException;

// Missing plural form in target
$comparator = new MessagePatternComparator(
    'en', 'fr',
    '{count, plural, one{# item} other{# items}}',
    'Les articles {count}'  // Missing plural form!
);

try {
    $comparator->validate();
} catch (MissingComplexFormException $e) {
    echo $e->getMessage();
    // "Argument 'count' has complex form 'PLURAL' in source (en) but is missing in target (fr)."

    echo $e->argumentName;     // 'count'
    echo $e->sourceArgType;    // ArgType::PLURAL
    echo $e->targetArgType;    // null (missing)
    echo $e->sourceLocale;     // 'en'
    echo $e->targetLocale;     // 'fr'
}

// Mismatched complex form types
$comparator = new MessagePatternComparator(
    'en', 'fr',
    '{count, plural, one{# item} other{# items}}',
    '{count, select, one{un article} other{des articles}}'  // SELECT instead of PLURAL!
);

try {
    $comparator->validate();
} catch (MissingComplexFormException $e) {
    echo $e->getMessage();
    // "Argument 'count' has complex form 'PLURAL' in source (en) but has 'SELECT' in target (fr)."

    echo $e->targetArgType;    // ArgType::SELECT
}

use Matecat\ICU\MessagePatternComparator;

$comparator = new MessagePatternComparator(
    'en', 'fr',
    '{count, plural, one{# item} other{# items}}',
    '{count, plural, one{# article} other{# articles}}'
);

// Check if patterns contain complex syntax
$comparator->sourceContainsComplexSyntax();  // true
$comparator->targetContainsComplexSyntax();  // true

// Get locales
$comparator->getSourceLocale();  // 'en'
$comparator->getTargetLocale();  // 'fr'

use Matecat\Locales\LanguageDomains;

// Get all language domains
$domains = LanguageDomains::getInstance();
$allDomains = $domains->getDomains();

// Get a specific domain
$domain = $domains->getDomain('technical');