Uploaded image for project: 'PUBLIC - Liferay Portal Community Edition'
  1. PUBLIC - Liferay Portal Community Edition
  2. LPS-70951

Using placeholders in {msg} with Soy doesn't work anymore

    Details

      Description

      When developing a piece of interface with Soy (to be included in a Metal component) there's a small bug that prevents {msg} with placeholders from working correctly.

      Steps to reproduce

      Create a new Soy file called MyTemplate.soy in a *-web bundle already configured for Metal development (with a package.json already set up, for example). Use this as the template:

      {namespace MyTemplate}
      
      /** No docs */
      {template .render}
        {let $dynamic: 'cool' /}
        <p>{msg desc=""}do-you-like-{$dynamic}-i18n{/msg}</p>
      {/template}
      

      Call gradle clean deploy on the bundle (no need to install it).

      Explore build/resources/main/META-INF/resources/ to see the results of the compilation process.

      Expected result

      Inside MyTemplate.soy.js you'll find an occurence of Liferay.Language.get.
      This will be followed by some later replacements on the resulting value. Something like this:

      /* (1) */ var MSG = Liferay.Language.get('do-you-like-x-i18n');
      /* (2) */ MSG.replace('{0}', '\x010\x01');
      

      Line (1) has been transformed from goog.getMsg to Liferay's Language.get.
      Line (2) replaces {N} MessageFormat placeholders from Soy's \x01N\x01 placeholders.

      Actual Result

      The resulting compiled code results in only the first line being outputted:

      /* (1) */ var MSG = Liferay.Language.get('do-you-like-x-i18n');
      

      and because the placeholder format is not fixed, Soy will not replace them in the final output.

      Source of the issue

      In ReplaceTranslationCommand.java there are 2 involved RegExp:

      RegExp A

      var (MSG_EXTERNAL_\d+) = goog\.getMsg\(\s*'([\w-\{\}\$]+)'\s*(?:,\s*\{([\s\S]+?)\})?\);
      

      RegExp B

      '.+'\s*:\s*([\d\w\._]+)+
      

      The RegExp A is used to identify compiled occurrences of {msg} directives, which are in the form

      /* (1) */ var MSG_EXTERNAL_NNNN = goog.getMsg(
      /* (2) */  'do-you-like-{$dynamic}-i18n',
      /* (3) */  { 'dynamic': '\x010\x01' });
      

      Where at line (3) an object which transforms "names" to placeholders is passed.

      RegExp B on the other hand is used to match inside this JavaScript object literal to identify names/placeholder pairs. They will be later used to construct replacements for the MessageFormat placeholders.

      This last RegExp simply doesn't work and doesn't find correctly every object property member.

      Proposed solution

      Simply replace the second RegExp with:

      \s*(['"])\w+\1\s*:\s*((['"])([^'"]+)\3)
      

      or

      \s*(['"])\w+\1\s*:\s*((['"])(.*)\3)
      

      which is also stronger in regards to using either ' or " as JS string delimiters.

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              michael.saechang Michael Saechang
              Reporter:
              pierpaolo.ramon Pier Paolo Ramon
              Participants of an Issue:
              Recent user:
              Esther Sanz
              Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved:
                Days since last comment:
                3 years, 39 weeks, 3 days ago

                  Packages

                  Version Package
                  7.0.X EE
                  Master