feat(intl): add localization support - #1294
Merged
Merged
Conversation
Member
Author
|
Documentation PR: tempestphp/tempestphp.com#86 |
innocenzi
marked this pull request as ready for review
June 22, 2025 15:15
Member
|
Nice, PR @innocenzi! I haven't reviewed all the code, but I like the API. Quick question, why was PHPUnit removed as a dev dependency from other sub-packages? |
Member
Author
I removed it as an attempt to fix that unknown CI error, since it was happening only for those packages. I'm not sure why none of the other packages depend on PHPUnit either |
brendt
previously requested changes
Jun 23, 2025
brendt
left a comment
Member
There was a problem hiding this comment.
Great PR! I had a couple of questions, but I think this is almost ready to merge
Member
|
I'm good to merge! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1114
This pull request's main goal is to add a new
tempest/intlpackage with a translator and a MessageFormat 2.0 implementation (parser and formatter included).I also moved
Tempest\Support\Number,Tempest\Support\Language, andTempest\Support\Localeto this package, because the scope makes sense.MessageFormat
Note
I chose to go ahead with MessageFormat 2.0 instead of 1.0 (which is built in PHP's
Intlextension) because this specification is more flexible and future-proof. For instance, it supports markup and custom functions.The
Tempest\Intl\MessageFormat\Formatter\MessageFormatterimplementation provides a lower-level way to format MessageFormat 2.0 messages.This would generally not be used in userland, but it's available (and used internally).
Note that the pluralization rules are generated thanks to publicly-available CLDR plural rules from the unicode project. To re-generate the class, we can just run the
bin/plural-rulesscript.Translator
The
Tempest\Intl\Translatorinterface has atranslateandtranslateForLocalemethod, which are both straightforward. They accept a translation key and arguments, and return the translated message (or the translation key on failure).When a translation is missing or has failed, the
TranslationMissorTranslationFailedevents will be dispatched, respectively.Messages
Messages are stored as YAML or JSON files. YAML is recommended because MF2 messages are often multiline, which is hard to work with in JSON. We could add support for PHP files as well, but the DX is better in YAML.
By default, Tempest will discover files like
messages.fr.yaml, where the locale part is a valid, known locale (eg.messages.abcd.yamlwill not be discovered, butlocales.en_UK.yamlwill).Discovery will add the file paths to the
IntlConfig, which will be used by theTempest\Intl\Catalogimplementation to load translation messages.Configuration
From now on, the current locale is stored in
Tempest\Intl\IntlConfigin thecurrentLocaleproperty.Future features that depend on the current locale should be built upon this. By default, the current locale will be
Locale::default(), which usesLocale::getDefault().