Skip to content
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

[Translation] Added intl message formatter. #27399

Merged
merged 11 commits into from Sep 4, 2018

Conversation

Nyholm
Copy link
Member

@Nyholm Nyholm commented May 28, 2018

Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets replaces #20007
License MIT
Doc PR

This PR will replace #20007 and continue the work from the original author.

I've have tried to address all comments made in the original PR.

*/
public function format($message, $locale, array $parameters = array())
{
$formatter = new \MessageFormatter($locale, $message);
Copy link
Contributor

Choose a reason for hiding this comment

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

When the parsing of this message fails you get a very non-descriptive exception message (Constructor failed). Might be good for DX to rethrow a more descriptive one.

*/
private function getFormatter(string $domain)
{
if (isset($this->formatters[$domain])) {
Copy link
Contributor

Choose a reason for hiding this comment

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

this could be reduced to:

return $this->formatters[$domain] ?? $this->formatters['_default'];

Copy link
Contributor

Choose a reason for hiding this comment

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

And we can declare return type also


public function testFormatWithNamedArguments()
{
if (PHP_VERSION_ID < 50500 || version_compare(INTL_ICU_VERSION, '4.8', '<')) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Checking for php version is redundant

"php": "^7.1.3",

@nicolas-grekas nicolas-grekas added this to the next milestone May 29, 2018
@Nyholm
Copy link
Member Author

Nyholm commented Jun 8, 2018

I've rebased this PR and updated according to feedback.

@@ -132,6 +132,15 @@ public function addResource($format, $resource, $locale, $domain = null)
}
}

/**
* @param string $domain
* @param MessageFormatterInterface $formatter
Copy link
Member

Choose a reason for hiding this comment

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

to be removed :)

Copy link
Member Author

Choose a reason for hiding this comment

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

Thank you. I added : void as return type.

/**
* @param string $domain
*
* @return MessageFormatterInterface
Copy link
Member

Choose a reason for hiding this comment

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

to be removed (and a real return type be used instead)

Copy link
Member Author

Choose a reason for hiding this comment

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

Thank you

@Nyholm
Copy link
Member Author

Nyholm commented Jul 23, 2018

Anything I can do to help review this?

@artursvonda
Copy link
Contributor

Love the change and allowing to get rid of special case of transChoice (over time).

The original PR mentioned something about storing format with the messages and I actually tend to agree with it. The format IS information that's directly coupled with actual messages (basically, a meta information about contents of the file). This becomes even more important if translations are coming from external source and are not part of source files. There already have been talks about allowing different caching mechanisms and sources (like database) so coupling domain to format in config would not allow for changes in message format without deployment (and would make syncing changes hard anyway).
Catalogues already support metadata so we can add formatter as additional key there and maybe think about making formatter metadata part of actual message which would allow even more granular transition of messages from one format to another.
Architecture wise this would mean a bigger change long term with messages probably being objects (or structs) containing metadata but short term we can just use similar strategy as in this PR but configure domain => formatter relation automatically based on metadata in translation files.

@nicolas-grekas
Copy link
Member

Added to project "Contracts" after comment #28210 (comment)

*/
public function choiceFormat($message, $number, $locale, array $parameters = array())
{
return $this->format($message, $locale, $parameters);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this kind of implementation right? Argument number is unused.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we shouldn't implement the ChoiceMessageFormatterInterface instead, it will disallow using the transChoice method which is right since we should only use the trans method for intl-formated message.

} catch (\Throwable $e) {
throw new \InvalidArgumentException('Invalid message format.', $e);
}
if (null === $formatter) {
Copy link
Member Author

Choose a reason for hiding this comment

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

It will never be null here

@nicolas-grekas
Copy link
Member

I like it, but I would make the new formatter accessible only through trans() and not through transChoice() which should support only the Symfony syntax.
This would pave the way to deprecating transChoice at a later point in time, following this comment from @Koc.
I'd suggest to wait for #28210 to be merged before rebasing this PR and resolving this very comment.

@nicolas-grekas
Copy link
Member

Some description of the format here:
https://messageformat.github.io/messageformat/page-guide

@Nyholm Nyholm force-pushed the intl-formatter branch 2 times, most recently from 7358b74 to daaceb0 Compare September 3, 2018 22:13
@Nyholm
Copy link
Member Author

Nyholm commented Sep 3, 2018

I've updated this PR.
I did some major changes. I removed support for multiple formatters. Instead, I added a FallbackFormatter.

With the fallback formatter we can support both "Symfony style plural" and intl messages at the same time. This will make sure we have a zero config solution for adding support for this new feature while all the old formats still works as expected.

Possible update: I could make the FallbackFormatter less generic by using the following constructor signature: FallbackFormatter::__construct(IntlMessageFormatter $first, MessageFormatter $second). The logic will be simpler if I do this change.

if (!\extension_loaded('intl')) {
$this->markTestSkipped(
'The Intl extension is not available.'
);
Copy link
Member

Choose a reason for hiding this comment

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

should be on one line


class IntlMessageFormatterTest extends \PHPUnit\Framework\TestCase
{
public function setUp()
Copy link
Member

Choose a reason for hiding this comment

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

should be protected

);
}

private function getMessageFormatter()
Copy link
Member

Choose a reason for hiding this comment

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

I think this can be inlined instead.

@@ -7,6 +7,7 @@ CHANGELOG
* Started using ICU parent locales as fallback locales.
* deprecated `TranslatorInterface` in favor of `Symfony\Contracts\Translation\TranslatorInterface`
* deprecated `MessageSelector`, `Interval` and `PluralizationRules`; use `IdentityTranslator` instead
* Added `IntlMessageFormatter` and`FallbackMessageFormatter`
Copy link
Member

Choose a reason for hiding this comment

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

missing space after and.

* file that was distributed with this source code.
*/

declare(strict_types=1);
Copy link
Member

Choose a reason for hiding this comment

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

AFAIK, we are not using this anywhere else, this should be removed.

return $this->secondFormatter->choiceFormat($message, $number, $locale, $parameters);
}

throw new LogicException(sprintf('The no formatter support plural translations.'));
Copy link
Member

Choose a reason for hiding this comment

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

The message is not so clear to me :) I suppose you meant No formatters support plural translations.

try {
$formatter = new \MessageFormatter($locale, $message);
} catch (\Throwable $e) {
throw new InvalidArgumentException(sprintf('Invalid message format. Reason: %s (error #%d)', intl_get_error_message(), intl_get_error_code()), 0, $e);
Copy link
Member

Choose a reason for hiding this comment

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

As an exception should end with a dot, I suggest to use Invalid message format (%s, error #%d). Same below

@Nyholm
Copy link
Member Author

Nyholm commented Sep 4, 2018

Thank you for the review, Ive updated the PR

{
try {
$result = $this->firstFormatter->format($message, $locale, $parameters);
} catch (\Throwable $e) {
Copy link
Member

Choose a reason for hiding this comment

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

Can we be more specific here? We should be as much as possible IMHO (same below.)

Copy link
Member Author

Choose a reason for hiding this comment

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

Do we want to be more specific?
I know the IntlMesaageFormatter only throws InvalidArgument, but isn’t it a good idea to catch everything to give the second formatter a change to run?

Copy link
Member

Choose a reason for hiding this comment

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

I agree with @nicolas-grekas

Copy link
Member

@fabpot fabpot left a comment

Choose a reason for hiding this comment

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

With one small comment. In a followup PR, we should deprecate the old way, deprecate transChoice and probably try to write a script that converts our proprietary format to the intl one. WDYT?

@@ -17,6 +17,7 @@
use Symfony\Component\Translation\Formatter\FallbackFormatter;
use Symfony\Component\Translation\Formatter\MessageFormatterInterface;


Copy link
Member

Choose a reason for hiding this comment

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

should be removed

use Symfony\Component\Translation\Formatter\FallbackFormatter;
use Symfony\Component\Translation\Formatter\MessageFormatterInterface;


Copy link
Member

Choose a reason for hiding this comment

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

should be reverted

@nicolas-grekas
Copy link
Member

In a followup PR, we should deprecate the old way, deprecate transChoice and probably try to write a script that converts our proprietary format to the intl one

💯 for both!

@Nyholm
Copy link
Member Author

Nyholm commented Sep 4, 2018

Thank you. PR updated.

I agree to deprecate transChoice

@fabpot
Copy link
Member

fabpot commented Sep 4, 2018

Thank you @Nyholm.

@fabpot fabpot merged commit 2a90931 into symfony:master Sep 4, 2018
Contracts automation moved this from WIP to DONE Sep 4, 2018
fabpot added a commit that referenced this pull request Sep 4, 2018
…, Nyholm)

This PR was merged into the 4.2-dev branch.

Discussion
----------

[Translation] Added intl message formatter.

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | replaces #20007
| License       | MIT
| Doc PR        |

This PR will replace #20007 and continue the work from the original author.

I've have tried to address all comments made in the original PR.

Commits
-------

2a90931 cs
fb30c77 Be more specific with what exception we catch
b1aa004 Only use the default translator if intl extension is loaded
f88153f Updates according to feedback
597a15d Use FallbackFormatter instead of support for multiple formatters
2aa7181 Fixes according to feedback
a325a44 Allow config for different domain specific formatters
b43fe21 Add support for multiple formatters
c2b3dc0 [Translation] Added intl message formatter.
19e8e69 use error
940d440 Make it a warning
@Nyholm Nyholm deleted the intl-formatter branch September 5, 2018 20:21
fabpot added a commit that referenced this pull request Oct 6, 2018
…from contracts (Nyholm, nicolas-grekas)

This PR was merged into the 4.2-dev branch.

Discussion
----------

[Translator] Deprecated transChoice and moved it away from contracts

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | no
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | n/a
| License       | MIT
| Doc PR        | Issue: symfony/symfony-docs#10264

This will address comment made here: #27399 (review)

This PR moves the `transChoice()` method away from Contracts and back to the component. I also reverted changes in the `IdentityTranslator`. I will still use the deprecated `MessageSelector` but this is not fine since `transChoice()` is also deprecated.

Commits
-------

dc5f3bf Make trans + %count% parameter resolve plurals
d870a85 [Translator] Deprecated transChoice and moved it away from contracts
@nicolas-grekas nicolas-grekas modified the milestones: next, 4.2 Nov 1, 2018
This was referenced Nov 3, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
Contracts
  
DONE
Development

Successfully merging this pull request may close these issues.

None yet

9 participants