Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[Translation] Remove TranslatorBagInterface to allow for optimized caching in 3.0#14530

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Closed
mpdude wants to merge14 commits intosymfony:2.8fromwebfactory:drop-translator-bag
Closed

[Translation] Remove TranslatorBagInterface to allow for optimized caching in 3.0#14530

mpdude wants to merge14 commits intosymfony:2.8fromwebfactory:drop-translator-bag

Conversation

mpdude
Copy link
Contributor

QA
Bug fix?no
New feature?no
BC breaks?no
Deprecations?yes
Tests pass?yes
Fixed tickets
LicenseMIT
Doc PRn/a

We would like theTranslator to be able to perform various optimizations on theMessageCatalogues it holds internally. One particular example is working with reduced catalogues for fallback locales that only contain the messages not present in one of the more preferred locales, or possibly do a lazy-loading of catalogues for fallback locales.

These optimizations are not possible as long as clients are able to retrieve theMessageCatalogue instances used inside theTranslator by means of theTranslatorBagInterface and expect them to be full-fledged and complete catalogue instances (so the initial attempt had to be reverted in#14315, also see#14380 for a discussion).

In other words,TranslatorBagInterface breaks a boundary of encapsulation important for optimizations.

The two clients of the interface inside Symfony are not really interested in the catalogues per se, but only need them to iterate along the fallback chain in order to figure out the locale ultimately used. This information can now be obtained through the newFallbackLocaleAwareInterface.

To be discussed:

  • In 3.0, shouldFallbackLocaleAwareInterface remain a dedicated interface or become part ofTranslatorInterface?
  • Shall we keep theTranslatorBagInterface in the future, especially ifTranslator does not implement it?

@@ -506,4 +522,19 @@ private function getConfigCacheFactory()

return $this->configCacheFactory;
}

private function getCatalogueInternal($locale = null)
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

We could rename this back togetCatalogue() and make it private once we do no longer implementTranslatorBagInterface (in 3.0).

Copy link
Contributor

Choose a reason for hiding this comment

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

can you add this note above.

@@ -213,54 +213,6 @@ public function testDifferentCacheFilesAreUsedForDifferentSetsOfFallbackLocales(
$this->assertEquals('bar', $translator->trans('bar'));
}

public function testPrimaryAndFallbackCataloguesContainTheSameMessagesRegardlessOfCaching()
Copy link
Contributor

Choose a reason for hiding this comment

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

it shoud be removed in3.0 rename it intotestLegacyPrimaryA.. instead and add

$this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED);

*
* @author Matthias Pigulla <mp@webfactory.de>
*/
interface FallbackLocaleAwareInterface
Copy link
Contributor

Choose a reason for hiding this comment

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

TranslatorLocaleAwareInterface ?

@@ -35,8 +35,8 @@ class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInter
*/
public function __construct(TranslatorInterface $translator)
{
if (!$translator instanceof TranslatorBagInterface) {
throw new \InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface and TranslatorBagInterface.', get_class($translator)));
if (!($translator instanceof TranslatorBagInterface && $translator instanceof FallbackLocaleAwareInterface)) {
Copy link
Member

Choose a reason for hiding this comment

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

requiring it to implement both is actually a BC break as not implementing FallbackLocaleAwareInterface was allowed previously. You are restricting the supported argument, and the BC promise only allows to widen it

Copy link
Member

Choose a reason for hiding this comment

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

the right solution would be to provide a Translator implementation which would implementFallbackLocaleAwareInterface on top ofTranslatorBagInterface and wrap the translator into this implementation when it implements TranslatorBagInterface but not FallbackLocaleAwareInterface. This would make things BC, avoid duplication between the DataCollectorTranslator and the LoggingTranslator and not have performance penalty for the normal case (given that the default translator implements the new interface)

@stof
Copy link
Member

stof commentedMay 4, 2015

@mpdude I just thought about another case where TranslatorBagInterface could be useful:https://github.com/willdurand/BazingaJsTranslationBundle/ is exposing translation catalogues to the JS code. Currently, it does that by reimplementing the loading itself (it gets all translation loaders from Symfony and gets all resources as well, all of which is done by the Translator) because TranslatorBagInterface was not available at that time. What would be the clean way toimplement such your case in your new architecture (duplicating the loading is not the clean way in the 2.6 architecture IMO, but it was probably the only way in the 2.3 architecture, which is why it is used)

@aitboudad
Copy link
Contributor

well I think we need to keepgetCatalogue and the optimize caching should be done by optimizingMessageCatalogue see#14526

@mpdude
Copy link
ContributorAuthor

@stof In the case of messages available in both the primary and in fallback catalogues, which set of messages do you think this bundle would need?

The problem is that if we burdenTranslator with general tasks like providing completeMessageCatalogue chains, it gets harder to optimize the data structures used internally for the "find best translation available" use case (thetrans() andtransChoice() methods).

We could, of course, internally use optimized structures for these methods plus a "complete" set ofMessageCatalogue chains for theTranslatorBagInterface-based use cases, but that would clearly be a nightmare to maintain and would not make a good example for the SRP.

So, what if we had two different classes (or services in the case of the full-stack framework):

The first one is where the resources and loaders are registered. You tell it your preferred order of locales, it will return a full-fledgedMessageCatalogue chain (expensive operation!).

The second one is theTranslator. It will initially obtain theMessageCatalogue from the first class, but then optimize/tweak things as it sees fit for thetrans() andtransChoice() methods. These optimized structures can be kept in the cache and will not be exposed to the outside world.

@stof
Copy link
Member

stof commentedMay 4, 2015

@mpdude This bundle would need anything needed to be able to reimplementtrans andtransChoice in JS. So it would need the full catalogues for any active locales (it currently supports activating multiple locales, in case the locale choice need to be done on the JS side, or to keep a single translation file for all locales to simplify the loading of the JS), but only fallback messages might be enough for other locales.

And I agree that delegating all the loading to a separate class might be a better architecture. It could also simplify a bunch of things:

  • lazy-loading of loaders could be implemented by implementing this interface in a lazy way (or relying of the DI feature to build the lazy implementation) instead of extending the Translator in FrameworkBundle, which would also make the lazy-loading available for people using DI+Translator outside Symfony
  • caching of catalogues could be implemented by composition instead of being in the main class dealing with loaders (which does not forbid caching the internal structures of the Translator class, which is a separate topic).

This is something I already thought about in the past. The hard part is the Translator class is currently designed to be extendable through inheritance. Extracting this logic into separate collaborators in a BC way will likely be very hard.

@aitboudad
Copy link
Contributor

@stof FYI I work on delegating all the loading :)

@stof
Copy link
Member

stof commentedMay 4, 2015

@aitboudad have you found a way to keep BC for people overwriting protected methods of the Translator to customize the Translator through its current extension points ?

@aitboudad
Copy link
Contributor

@stof see an initial work forDelegationLoader I'll complete it soon, I think we need to deprecateSymfony\Bundle\FrameworkBundle\Translation\Translator.
To avoid BC we will create a new translator service and deprecate the default one.

@aitboudad
Copy link
Contributor

@mpdude why we can't probably not move that responsibility out into another class ? until now
I have only one issue aboutinitializeCatalogue, I'll see how to deal with it.

@stof should we move handling fallback catalogues intoDelegationLoader or by composition instead ?

@fabpot
Copy link
Member

What is the status of this PR? ping@aitboudad

@mpdude
Copy link
ContributorAuthor

I rebased this branch and fixed the various issues from the first review by@aitboudad and@stof.

This won't take us to the ultimate goal of a better and more efficientTranslator (#13948) because we'd probably also need to factor loading out of theTranslator and prohibit inheritance (this andthat comment and maybe something like the#14622 or#14671 PRs?)

Anyway, this IMO improves our situation because we can (in 3.0) remove an interface that definetly is a show-stopper.

@@ -39,6 +44,12 @@ public function __construct(TranslatorInterface $translator)
throw new \InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface and TranslatorBagInterface.', get_class($translator)));
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Need to fix that. The interface is deprecated and must not be required.

@aitboudad
Copy link
Contributor

@fabpot ll try to finish#14622 today as I think it's more efficient than this one(ideally we should have something likehttps://github.com/openl10n/openl10n-translation/tree/master/src/Openl10n/Component/Translation/MessageCatalogue)

@mpdudempdude changed the title[RFC] [Translation] Remove TranslatorBagInterface to allow for optimized caching in 3.0[Translation] Remove TranslatorBagInterface to allow for optimized caching in 3.0Oct 3, 2015
…or a translation.That way, clients that need this information need no longer obtain the MessageCatalogues through the TranslatorBagInterface.This is a first step towards better encapsulation. Our final goal is to be able to use optimized implementations of the MessageCatalogue without leaking those to our clients.
@mpdude
Copy link
ContributorAuthor

@symfony/deciders I would like to ask for your vote on this.

I believe that removing the TranslatorBagInterface is one important prerequisite for more efficient caching and/or loading inside the Translator because it improves encapsulation.

With the current state of this PR, one important thing to note is that we leave clients without a way to retrieve the message catalogue from the translator, a feature added in 2.6 "by accident" (it would not have been necessary for the feature we added back then).

To provide an alternate means of retrieving the catalogue is an on-going effort in#14622 and#14671, but with the internal structure ofTranslator (different code paths, mixing several concerns,protected methods and@api) I am unsure if we can make it.

So, the decision you need to make is whether the improvement this PR brings is worth this possible annoyance for users of theTranslatorBagInterface in case that no other replacement for it can be provided.

Note that@stofrefers to one third-party bundle that workswithout this interface by implementing the loading itself.

(The failing test is for PHP 7 is completely unrelated.)

@nicolas-grekasnicolas-grekas added this to the3.x milestoneDec 6, 2016
@nicolas-grekas
Copy link
Member

I think we don't need this one: optimized caching is already dealt with on PHP7, where static arrays and static strings are far superior optimizing strategies. Thus, no need to do anything more on our side to me.

@jakzal
Copy link
Contributor

@mpdude any thoughts on what Nicolas said?

@nicolas-grekas
Copy link
Member

Closing as explained. Of course, please reopen if you don't agree.

@mpdude
Copy link
ContributorAuthor

I opened this a while ago when I was working on a project where we had issues due to a large number of languages supported and comprehensive catalogs.

We found other ways to work around this and I cannot tell whether the problem would still appear on PHP7.

So, closing this is fine for me. Will reopen it or make a new case should I run into it again.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers
No reviews
Assignees
No one assigned
Projects
None yet
Milestone
3.4
Development

Successfully merging this pull request may close these issues.

7 participants
@mpdude@stof@aitboudad@fabpot@nicolas-grekas@jakzal@javiereguiluz

[8]ページ先頭

©2009-2025 Movatter.jp