Search code examples
aemsightly

Evaluating expression and pass as argument in Sightly AEM


I have the following Sightly expression:

 <li data-sly-call="${linkTemplate.dynamicLink @ section='education', 
    url='/en/life-career-events.html', text=${'comp.masthead.navigation.home' @ i18n}}">
 </li>

The dynamiclink template is as follows:

<div data-sly-template.dynamicLink="${@ section, url, text}"
     data-sly-use.membersNav="${'com.comp.cms.component.masthead.MembersNavigation' @ section=section}">
  <a data-sly-attribute.class="${membersNav.cssClass}" href="${url}">${text}</a>
</div>

This doesn't work because text=${'comp.masthead.navigation.home' @ i18n} isn't evaluated as a string and then passed into the dynamiclink.

Is this possible? Can I evaluate and assign to a variable or do I have to create a new template when I want to evaluate i18n lookups?


Solution

  • Sightly 1.1 doesn't allow to have expressions within expressions, and there's no plan to change that for now.

    Hacking the solution:

    There's a trick: data-sly-test can be (ab)used to set variables. It's not really a recommended way to do though, unless you have a real condition, because this will mislead someone who reads the template in thinking that the intention was to have an actual condition.

    The trick goes like that: an identifier can be provided to data-sly-test, which will expose the result of the test as a variable. Additionally, data-sly-test will be considered true, unless the resulting string is empty.

    For e.g.:

    <p data-sly-test.spanishAsset="${'Asset' @ i18n, locale='es'}">${spanishAsset}</p>
    

    Outputs:

    <p>Recurso</p>
    

    So in your case, you could write:

    <li data-sly-test.linkText="${'comp.masthead.navigation.home' @ i18n}"
        data-sly-call="${linkTemplate.dynamicLink @ section='education', 
    url='/en/life-career-events.html', text=linkText}">
    </li>
    

    A cleaner solution

    As you probably don't want to explain to all the users of this template that they have to write such a hack, and instead of having two separated templates for translated and non-translated texts, you could instead leverage optional templates parameters. So you might for e.g. have a noI18n optional parameter.

    The call would then be as simple as it can be:

    <!--/* Translating would be the default behavior */-->
    <li data-sly-call="${linkTemplate.dynamicLink @
        section='education', 
        url='/en/life-career-events.html',
        text='comp.masthead.navigation.home'}"></li>
    <!--/* Or translating could be turned off */-->
    <li data-sly-call="${linkTemplate.dynamicLink @
        section='education', 
        url='/en/life-career-events.html',
        text='my text...',
        noI18n=true}"></li>
    

    The template would then have two data-sly-test conditions for the two cases (note that the data-sly-unwrap attributes can be dropped in AEM 6.1+):

    <div data-sly-template.dynamicLink="${@ section, url, text, noI18n}"
         data-sly-use.membersNav="${'com.comp.cms.component.masthead.MembersNavigation'
             @ section=section}">
        <a href="${url}" data-sly-attribute.class="${membersNav.cssClass}">
            <sly data-sly-test="${noI18n}" data-sly-unwrap>${membersNav.text}</sly>
            <sly data-sly-test="${!noI18n}" data-sly-unwrap>${membersNav.text @ i18n}</sly>
        </a>
    </div>
    

    Optionally, to keep the template as simple as possible and to remove those conditions, you could also make the Use-API do the translation, depending on the noI18n optional parameter:

    <div data-sly-template.dynamicLink="${@ section, url, text, noI18n}"
         data-sly-use.membersNav="${'com.comp.cms.component.masthead.MembersNavigation'
             @ section=section, noI18n=noI18n}">
        <a href="${url}" data-sly-attribute.class="${membersNav.cssClass}">
            ${membersNav.text}
        </a>
    </div>
    

    The proper code for the logic to translate a string is:

    Locale pageLang = currentPage.getLanguage(false);
    I18n i18n = new I18n(slingRequest.getResourceBundle(pageLang));
    String text = i18n.get("Enter a search keyword");