Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Some ideas to improve performance of the Translator component #13948

Closed
@javiereguiluz

Description

@javiereguiluz

The problem

Recently some people have raised concerns about Translator component performance (see #13676 for example). I was inspecting the dumped container for production environment to get more information about this component and I saw the following problems:

1. All translation loaders and dumpers are instantiated and loaded, no matter which ones you use:

protected function getTranslation_LoaderService()
{
    $a = $this->get('translation.loader.xliff');
    $this->services['translation.loader'] = $instance = new \Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader();
    $instance->addLoader('php', $this->get('translation.loader.php'));
    $instance->addLoader('yml', $this->get('translation.loader.yml'));
    $instance->addLoader('xlf', $a);
    $instance->addLoader('xliff', $a);
    $instance->addLoader('po', $this->get('translation.loader.po'));
    $instance->addLoader('mo', $this->get('translation.loader.mo'));
    $instance->addLoader('ts', $this->get('translation.loader.qt'));
    $instance->addLoader('csv', $this->get('translation.loader.csv'));
    $instance->addLoader('res', $this->get('translation.loader.res'));
    $instance->addLoader('dat', $this->get('translation.loader.dat'));
    $instance->addLoader('ini', $this->get('translation.loader.ini'));
    $instance->addLoader('json', $this->get('translation.loader.json'));
    return $instance;
}

protected function getTranslation_Dumper_QtService()
{
    return $this->services['translation.dumper.qt'] = new \Symfony\Component\Translation\Dumper\QtFileDumper();
}

protected function getTranslation_Dumper_ResService()
{
    return $this->services['translation.dumper.res'] = new \Symfony\Component\Translation\Dumper\IcuResFileDumper();
}

// ...

Same thing happens with the translation dumpers:

protected function getTranslation_WriterService()
{
    $this->services['translation.writer'] = $instance = new \Symfony\Component\Translation\Writer\TranslationWriter();
    $instance->addDumper('php', $this->get('translation.dumper.php'));
    $instance->addDumper('xlf', $this->get('translation.dumper.xliff'));
    $instance->addDumper('po', $this->get('translation.dumper.po'));
    $instance->addDumper('mo', $this->get('translation.dumper.mo'));
    $instance->addDumper('yml', $this->get('translation.dumper.yml'));
    $instance->addDumper('ts', $this->get('translation.dumper.qt'));
    $instance->addDumper('csv', $this->get('translation.dumper.csv'));
    $instance->addDumper('ini', $this->get('translation.dumper.ini'));
    $instance->addDumper('json', $this->get('translation.dumper.json'));
    $instance->addDumper('res', $this->get('translation.dumper.res'));
    return $instance;
}

2. All resources for all locales are loaded, no matter which ones you use:

protected function getTranslator_DefaultService()
{
    // ...

    $instance->setFallbackLocales(array(0 => 'es'));
    $instance->addResource('xlf', ($this->targetDirs[3].'/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf'), 'af', 'validators');
    $instance->addResource('xlf', ($this->targetDirs[3].'/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf'), 'ar', 'validators');
    $instance->addResource('xlf', ($this->targetDirs[3].'/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf'), 'az', 'validators');
    $instance->addResource('xlf', ($this->targetDirs[3].'/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf'), 'bg', 'validators');
    $instance->addResource('xlf', ($this->targetDirs[3].'/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf'), 'ca', 'validators');
    $instance->addResource('xlf', ($this->targetDirs[3].'/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf'), 'cs', 'validators');
    $instance->addResource('xlf', ($this->targetDirs[3].'/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf'), 'cy', 'validators');
    // ... hundreds of additional lines
}

The solution

1. We could solve this problem with a technique similar to the templating engines selector:

framework:
    # ...
    templating:
        engines: ['twig', 'php']

In the case of translator:

framework:
    # ...
    translator:
        loaders: ['yml', 'xliff']
        dumpers: ['php']

To maintain backwards compatibility, these options could be null by default, meaning that all loaders/dumpers should be loaded.

2. We could solve this problem defining a new active_locales option to explicitly define the list of locales which will be used in the application:

framework:
    # ...
    default_locale: 'en'
    active_locales: ['es', 'en', 'fr', 'de']

Again, to maintain backwards compatibility, this new option would default to null to load all resources for all locales.

The benchmark

In my tests, I modified the generated container commenting/removing the lines that instantiate all the unused loaders/dumpers and I also removed all the translation resources files except the ones for the active locale. A quick before/after comparison made with Blackfire gave me around 10% performance increase in CPU time, 2.64% memory consumption reduction and about 600 less PHP function calls.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions