Skip to content

feat(intl): add localization support #1294

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Jun 24, 2025
Merged

Conversation

innocenzi
Copy link
Member

@innocenzi innocenzi commented Jun 21, 2025

Closes #1114

This pull request's main goal is to add a new tempest/intl package with a translator and a MessageFormat 2.0 implementation (parser and formatter included).

I also moved Tempest\Support\Number, Tempest\Support\Language, and Tempest\Support\Locale to 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 Intl extension) because this specification is more flexible and future-proof. For instance, it supports markup and custom functions.

The Tempest\Intl\MessageFormat\Formatter\MessageFormatter implementation 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-rules script.

Translator

The Tempest\Intl\Translator interface has a translate and translateForLocale method, which are both straightforward. They accept a translation key and arguments, and return the translated message (or the translation key on failure).

$translator->translate('hello', name: 'Jon Doe'); // Hello, Jon Doe!

When a translation is missing or has failed, the TranslationMiss or TranslationFailed events 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.yaml will not be discovered, but locales.en_UK.yaml will).

Discovery will add the file paths to the IntlConfig, which will be used by the Tempest\Intl\Catalog implementation to load translation messages.

Configuration

From now on, the current locale is stored in Tempest\Intl\IntlConfig in the currentLocale property.

Future features that depend on the current locale should be built upon this. By default, the current locale will be Locale::default(), which uses Locale::getDefault().

@innocenzi innocenzi changed the title feat(i18n): add internationalization package feat(i18n): add intl package Jun 21, 2025
@innocenzi innocenzi changed the title feat(i18n): add intl package feat(intl): add intl package Jun 21, 2025
@innocenzi
Copy link
Member Author

Documentation PR: tempestphp/tempest-docs#86

@innocenzi innocenzi marked this pull request as ready for review June 22, 2025 15:15
@innocenzi innocenzi changed the title feat(intl): add intl package feat(intl): add localization support Jun 22, 2025
@aidan-casey
Copy link
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?

@innocenzi
Copy link
Member Author

Quick question, why was PHPUnit removed as a dev dependency from other sub-packages?

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
brendt previously requested changes Jun 23, 2025
Copy link
Member

@brendt brendt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great PR! I had a couple of questions, but I think this is almost ready to merge

@brendt
Copy link
Member

brendt commented Jun 24, 2025

I'm good to merge!

@innocenzi innocenzi merged commit 17eeebc into tempestphp:main Jun 24, 2025
78 of 79 checks passed
@innocenzi innocenzi deleted the feat/i18n branch June 24, 2025 08:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Internationalization support
3 participants