Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony 3 or 4 Custom Translation Loader

I am very confused by symfony translation module. How can one configure a custom translation loader in the config files?

I have my custom loader an it works, based on this example: https://symfony.com/doc/current/components/translation/custom_formats.html

This works, if I put it in a controller

        $translator = new Translator( 'de' );
        $translator->addLoader( 'my_format', new MyCsvLoader() );
        $translator->addResource( 'my_format', $root . '/translations/translations.csv', 'de' );

        var_dump( $translator->trans( 'LB_ABOUT' ) );

But I cannot figure it out how can I register this as my "default" translation loader; as this should be used by default.

https://symfony.com/doc/current/reference/dic_tags.html#dic-tags-translation-loader

translation.yaml

framework:
    default_locale: 'en'
    translator:
        paths:
            - '%kernel.project_dir%/translations/'
        fallbacks:
            - '%locale%'

services.yaml:

App\Translate\MyCsvLoader:
    tags:
        - { name: translation.loader, alias: csv }
like image 776
klodoma Avatar asked Feb 09 '18 08:02

klodoma


1 Answers

i did some test and your configuration is ok. But you have to respect some rules to make it right. Symfony is trying to load catalog from a locale. So you have to put this locale in your filename: translations.de.csv

Like i said in my comment the loader is only to load data then the magic happens and symfony take care to put messages in the catalog. The right loader is resolved and use by a DelegatingLoader class, that's why you have to configure an alias in the tag's service.

here a demo:

Services.yaml

App\Translate\MyCsvLoader:
        tags:
            - { name: translation.loader, alias: csv }

Translation config

framework:
    default_locale: 'en'
    translator:
        default_path: '%kernel.project_dir%/translations'
        fallbacks:
            - '%locale%'

Loader Service

<?php

namespace App\Translate;

use Symfony\Component\Translation\Exception\NotFoundResourceException;
use Symfony\Component\Translation\Loader\FileLoader;

class MyCsvLoader extends FileLoader
{
    private $delimiter = ';';
    private $enclosure = '"';
    private $escape = '\\';

    /**
     * {@inheritdoc}
     */
    protected function loadResource($resource)
    {
        $messages = [];

        try {
            $file = new \SplFileObject($resource, 'rb');
        } catch (\RuntimeException $e) {
            throw new NotFoundResourceException(sprintf('Error opening file "%s".', $resource), 0, $e);
        }

        $file->setFlags(\SplFileObject::READ_CSV | \SplFileObject::SKIP_EMPTY);
        $file->setCsvControl($this->delimiter, $this->enclosure, $this->escape);

        foreach ($file as $data) {
            if ('#' !== substr($data[0], 0, 1) && isset($data[1]) && 2 === \count($data)) {
                $messages[$data[0]] = $data[1];
            }
        }

        return $messages;
    }

    /**
     * Sets the delimiter, enclosure, and escape character for CSV.
     *
     * @param string $delimiter Delimiter character
     * @param string $enclosure Enclosure character
     * @param string $escape    Escape character
     */
    public function setCsvControl($delimiter = ';', $enclosure = '"', $escape = '\\')
    {
        $this->delimiter = $delimiter;
        $this->enclosure = $enclosure;
        $this->escape    = $escape;
    }
}

Controller

/**
 * @Route("/{_locale}/test", name="test", requirements={"_locale": "en|fr"})
 */
public function index()
{
    return $this->render('index.html.twig');
}

Twig

{% extends 'base.html.twig' %}

{% block body %}
    <p>{{ 'symfony.great'|trans }}</p>
{% endblock %}

messages.en.csv

symfony.great;Symfony is great

messages.fr.csv

symfony.great;Symfony est génial
like image 146
GuillaumeL Avatar answered Oct 01 '22 21:10

GuillaumeL