Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2 translation yaml array and twig loop

I am trying to have twig convert an array from the translation file

// messages.en.yml

termsAndConditions:
  title: Terms and Conditions
  paragraph:
    - Paragraph text...blah blah...1
    - Paragraph text...blah blah...2
    - Paragraph text...blah blah...3
    - Paragraph text...blah blah...n

// termsandconditions.html.twig

// tried...

{% for i in range(1,termsAndConditions.paragraph|length) -%}
    <p>{% trans %}termsAndConditions.paragraph. {{ i }}{% endtrans %}</p>
{%- endfor %}

// and tried...

{% for i in range(1,termsAndConditions.paragraph|length) -%}
   <p>{{ 'termsAndConditions.paragraph.' ~ i ~ |trans }}</p>
{%- endfor %}
like image 818
Eddie Jaoude Avatar asked Jan 09 '15 20:01

Eddie Jaoude


1 Answers

You need to use pairs of keys: values to get things to work:

// messages.en.yml
termsAndConditions:
  title: Terms and Conditions
  paragraph:
    1: Paragraph text...blah blah...1
    2: Paragraph text...blah blah...2
    3: Paragraph text...blah blah...3
    4: Paragraph text...blah blah...n

Also and due to the fact that you want to use a variable for your translation, access to the translation this way {{('termsAndConditions.paragraph.'~i)|trans }}.

I've hardcoded 4 instead of termsAndConditions.paragraph|length. Not really sure if you can access that from a twig template...

// termsandconditions.html.twig
{% for i in range(1,4) -%}
   <p>{{('termsAndConditions.paragraph.'~i)|trans}}</p>
{%- endfor %}

It should work. Hope it helps.

UPDATE

termsAndConditions.paragraph|length makes no sense unless you've defined in the template the variable or you've injected the variable through the controller.

Solutions

Solution 1. In your controller, access the yaml and get the number of translations, then pass it to the template and that's it.

Solution 2. Create a service and inject the translator service to it. In the controller create a method that calculates the number of elements of a particular key. Injecting the translator service is better than reading the yaml directly as it caches the catalogue when it reads it.

Solution 3. Same as 2 but creating a twig filter. I'm going to go for this one as it seems kind of fun.

Solution 3

Let's start by creating the Extension:

namespace Acme\DemoBundle\Twig\Extension;

class TransLengthExtension extends \Twig_Extension
{
    private $translator;

    public function __construct($translator) {
        $this->translator = $translator;
    }


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

    public function translengthFilter($id, $domain = null)
    {
        if (null === $domain) {
            $domain = 'messages';
        }

        $i = 0;
        $g = $this->translator->getMessages();
        foreach($g["messages"] as $key => $message) {
            if(substr( $key, 0, strlen($id) ) === $id ) {
                $i++;
            }
        }

        return $i;
    }

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

As you can see above, it calculates the number of $id occurrences in the translation catalogue. Translator takes care of locale, loading the appropiate catalogue and so on. It also caches results which is really good in terms of performance.

Register the service injecting the translator and registering as a twig extension:

services:
    acme.twig.acme_extension:
        class: Acme\DemoBundle\Twig\Extension\TransLengthExtension
        arguments: 
            - "@translator"
        tags:
            - { name: twig.extension }

Now, in your template:

{% set end = 'termsAndConditions.paragraph'|translength %}
{% for i in range(1,end) -%}
   <p>{{('termsAndConditions.paragraph.'~i)|trans}}</p>
{%- endfor %}

Hope it helps.

like image 80
acontell Avatar answered Oct 21 '22 06:10

acontell