Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
95.83% |
23 / 24 |
|
50.00% |
1 / 2 |
CRAP | |
0.00% |
0 / 1 |
| Plural | |
95.83% |
23 / 24 |
|
50.00% |
1 / 2 |
9 | |
0.00% |
0 / 1 |
| __construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| process | |
95.65% |
22 / 23 |
|
0.00% |
0 / 1 |
8 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * @license GPL-2.0-or-later |
| 4 | * @file |
| 5 | */ |
| 6 | |
| 7 | namespace Wikimedia\Leximorph\Handler; |
| 8 | |
| 9 | use Wikimedia\Leximorph\Provider; |
| 10 | |
| 11 | /** |
| 12 | * Plural |
| 13 | * |
| 14 | * The Plural class selects the correct text form based on a numeric count and language-specific |
| 15 | * pluralization rules from the Unicode CLDR. It processes a number along with an array of text options, |
| 16 | * returning the appropriately pluralized text. |
| 17 | * |
| 18 | * Usage Example: |
| 19 | * <code> |
| 20 | * echo $plural->process( 3, [ 'article', 'articles' ] ); |
| 21 | * </code> |
| 22 | * |
| 23 | * @since 1.45 |
| 24 | * @author Doğu Abaris (abaris@null.net) |
| 25 | * @license https://www.gnu.org/copyleft/gpl.html GPL-2.0-or-later |
| 26 | */ |
| 27 | class Plural { |
| 28 | |
| 29 | /** |
| 30 | * Initializes the Plural handler with the given language code and provider. |
| 31 | * |
| 32 | * @param Provider $provider The provider instance to use. |
| 33 | * |
| 34 | * @since 1.45 |
| 35 | */ |
| 36 | public function __construct( |
| 37 | private readonly Provider $provider, |
| 38 | ) { |
| 39 | } |
| 40 | |
| 41 | /** |
| 42 | * Selects and returns the pluralized text form based on a numeric count. |
| 43 | * |
| 44 | * This method evaluates the provided numeric count using language-specific pluralization rules |
| 45 | * derived from the Unicode CLDR. It then selects the appropriate text form from the provided |
| 46 | * array of alternatives, taking into account any explicit plural forms if specified. |
| 47 | * |
| 48 | * @param float $count The numeric count to evaluate. |
| 49 | * @param string[] $forms An array of text forms for pluralization. |
| 50 | * |
| 51 | * @since 1.45 |
| 52 | * @return string The pluralized text corresponding to the count. |
| 53 | */ |
| 54 | public function process( float $count, array $forms ): string { |
| 55 | // For "explicit" forms such as "0=No items", "1=One item", or "other=Items" |
| 56 | // we’ll store them in an associative array if we parse them that way. |
| 57 | $explicitForms = []; |
| 58 | |
| 59 | // For "default" (non-explicit) forms such as [ 'item', 'items' ], |
| 60 | // we store them in a sequential array with integer keys. |
| 61 | $defaultForms = []; |
| 62 | |
| 63 | // Separate explicit forms ("n=text") from default forms |
| 64 | foreach ( $forms as $form ) { |
| 65 | if ( str_contains( $form, '=' ) ) { |
| 66 | [ |
| 67 | $key, |
| 68 | $text, |
| 69 | ] = explode( '=', $form, 2 ); |
| 70 | // If key is purely numeric AND matches $count, return immediately: |
| 71 | if ( is_numeric( $key ) && (float)$key === $count ) { |
| 72 | return $text; |
| 73 | } |
| 74 | // Otherwise, treat it as an explicit string key |
| 75 | $explicitForms[$key] = $text; |
| 76 | } else { |
| 77 | // Default form |
| 78 | $defaultForms[] = $form; |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | // Figure out the plural category: "one", "few", "other", etc. |
| 83 | $pluralType = $this->provider->getPluralProvider()->getPluralRuleType( $count ); |
| 84 | |
| 85 | // If we have an explicit form matching $pluralType` as a key, use it: |
| 86 | // e.g., "one" => "Item", "other" => "Items" |
| 87 | if ( array_key_exists( $pluralType, $explicitForms ) ) { |
| 88 | return $explicitForms[$pluralType]; |
| 89 | } |
| 90 | |
| 91 | // Otherwise, fallback to the default forms (sequential) |
| 92 | // If we find a default that exactly matches $pluralType as a string, use that: |
| 93 | $foundKey = array_search( $pluralType, $defaultForms, true ); |
| 94 | if ( $foundKey !== false ) { |
| 95 | return $defaultForms[$foundKey]; |
| 96 | } |
| 97 | |
| 98 | // Else, use the numeric index from the language’s plural rules |
| 99 | // (e.g. 0 => singular form, 1 => plural form, etc.) |
| 100 | if ( count( $defaultForms ) > 0 ) { |
| 101 | $index = $this->provider->getPluralProvider()->getPluralRuleIndexNumber( $count ); |
| 102 | // Guard in case $index is out of range |
| 103 | $index = min( $index, count( $defaultForms ) - 1 ); |
| 104 | |
| 105 | return $defaultForms[$index]; |
| 106 | } |
| 107 | |
| 108 | // If no forms were provided at all, just return an empty string |
| 109 | return ''; |
| 110 | } |
| 111 | } |