feat: add plural translations - #20
HarshMN2345 wants to merge 3 commits into
Conversation
Format ICU MessageFormat plural translations with the CLDR rules of the language that has the translation. getPlural returns a plural translation, getText fills plural placeholders in the language of the text it returns, and languages that load another language's translations can name the locale whose plural rules apply.
|
| public function getPlural(string $key, int $count, string|null $default = self::DEFAULT_DYNAMIC_KEY): ?string | ||
| { | ||
| return $this->format($this->default, $key, $count) ?? ($default === self::DEFAULT_DYNAMIC_KEY ? '{{'.$key.'}}' : $default); | ||
| } |
There was a problem hiding this comment.
This locale-sensitive feature has no automated behavioral coverage. Add observable tests for getPlural() and plural placeholders that cover CLDR category selection, fallback-language rule selection, malformed patterns, missing keys and defaults, and exception mode. Without these tests, the feature's core behavior can regress while the existing suite remains green.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/Locale/Locale.php
Line: 190-193
Comment:
**Plural Behavior Lacks Tests**
This locale-sensitive feature has no automated behavioral coverage. Add observable tests for `getPlural()` and plural placeholders that cover CLDR category selection, fallback-language rule selection, malformed patterns, missing keys and defaults, and exception mode. Without these tests, the feature's core behavior can regress while the existing suite remains green.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Run the suite with the intl extension so the plural paths are exercised, and cover CLDR category selection, the plural rules of a language that loads another language's translations, fallback formatting, invalid patterns and defaults. Plural counts accept floats, since CLDR gives fractions their own category, and patterns can take other ICU arguments. An invalid pattern now reports itself instead of looking like a missing translation. The intl extension moves to require: it is needed by a method on the only class this library has. The PHP constraint follows the typed class constant the code already uses.
What does this PR do?
Adds plural translations, so Appwrite emails can show a relative expiry like "This code will expire in 15 minutes" with the correct plural form in every language (appwrite/appwrite#13726).
getPlural(string $key, int $count, ?string $default)formats a translation written as an ICU MessageFormat pattern with acountargument, e.g.{count, plural, one {через # минуту} few {через # минуты} many {через # минут} other {через # минуты}}. It uses the CLDR plural rules of the language that has the translation, and falls back to the fallback language when the key is missing or the pattern doesn't parse.getText()takesplurals: ['expire' => ['emails.expire.minutes', 15]]. Each plural placeholder is formatted in the same language as the text it fills, so an English fallback sentence doesn't get a Russian phrase.setLanguageFromArray()andsetLanguageFromJSON()take an optional locale whose plural rules apply. Without it, a code that loads another language's file would pick the wrong form (Serbian rules on English text render "in 21 minute").Plurals need
ext-intl, added as a suggestion. The rules come from ICU, which ships them for every language even with English-only ICU data. Existing methods are unchanged.Test Plan
composer lint,composer check(PHPStan max) andcomposer testpass.{{key}}, the given default, or an exception when exceptions are onsetLanguageFromJSON('sr', 'en.json', 'en')→ "in 21 minutes"; without the rules locale → "in 21 minute"