Symfony: Load resources into the Translator from within a Service

Quentin

I'm working on a Symfony (2.7.4) website where some users have their own language resources for their own locales. For example, a user might have two locales (for example fr and en) and another user could also have one or all of these locales.

Each user has the ability to edit its own translations in a third party app, so translations are not shared between users.

I would like to be able to load the appropriate (YML or XLIFF) resources file when accessing a user's page, based on the locale (which is defined in the URL) and the user (could be its ID or anything that identifies it).

For example, when visiting user99.my-domain.ext/fr/ I'd like to add [base_directory]/user99/messages.fr.yml to the resources loaded by the Translator so it overrides the keys in the base messages.fr.yml.

I've tried to inject the Translator in my service, but I can only use it for reading translations, not adding any. What would be the best way to do that? Or is doing it in a service is too late? Maybe the Kernel is a better place?

Any help is appreciated!

Note: I'm using the YAML format in my examples, but any of the Symfony-known formats is eligible.

Quentin

I chose to use a custom Twig filter, so I can decide when I want user specific translations and when I want generic ones.

Here's my extension (my users are in fact Domain instances):

<?php

// src/AppBundle/Twig/DomainTranslationExtension

namespace AppBundle\Twig;

use AppBundle\Document\Domain;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Translation\Loader\YamlFileLoader;
use Symfony\Component\Translation\Translator;

class DomainTranslationExtension extends \Twig_Extension {

    /**
     * @var ContainerInterface
     */
    protected $container;

    /**
     * @var Translator
     */
    protected $translator;

    /**
     * @var string
     */
    protected $locale;

    /**
     * @var Domain
     */
    protected $domain;

    public function setContainer(ContainerInterface $container) {
        $this->container = $container;
        $this->locale = $this->container->get('request_stack')->getMasterRequest()->getLocale();

        $domainService = $this->container->get('app.domain_service');
        $this->domain = $domainService->getDomain();

        // TODO: File loading error check
        $this->translator = new Translator($this->locale);
        $this->translator->addLoader('yaml', new YamlFileLoader());
        $this->translator->addResource('yaml', 'path/to/domain-translations/' . $this->domain->getSlug() . '/messages.' . $this->locale . '.yml', $this->locale);
    }

    public function getFilters() {
        return array(
            new \Twig_SimpleFilter('transDomain', array($this, 'transDomain')),
        );
    }

    public function transDomain($s) {
        $trans = $this->translator->trans($s);
        // Falling back to default translation if custom isn't available
        if ($trans == $s) {
            $trans = $this->container->get('translator')->trans($s);
        }
        return $trans;
    }

    public function getName() {
        return 'app_translation_extension';
    }

}

Declared like that in app/config/services.yml:

app.domain_service:
    class: AppBundle\Services\DomainService
    arguments: [ @request_stack, @doctrine_mongodb, @translation.loader ]

And used like that in a Twig file:

{{ 'my.translation.key'|transDomain }}

I hope this helps, thanks!

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related