1

Before we were using mustache for template rendering, we had a PHP class that we used to translate text for localization. What it basically did, is that it accepted a variable number of parameters, searched for the translation for the first parameter in the database, then replaced in the variables in the translation to their respective parts. Below you will see the definition of the translating function this class used:

function translateText($text, $param1, $param2, ...., $paramX) {
    // search for the $text in the database, and retrieve the translation for it
    // if params are present, replace the %d strings from the translated text, with the params
}

For example, I could have inputed something like this to the function:

translateText("%0, please fetch me the bread", "Adam");

which would have been translated in Hungarian to

Add ide a kenyeret %0

Then the %0 parameter would have been replaced with my name, which was inputed for the second parameter in the function.

I tried to do something simmilar with mustache and it's lambda capability and reusing my old function. It looks something like this:

function($text, $helper) { 
   preg_match_all("/{{[#a-zA-Z0-9._-]+}}/", $text, $matches);
   $translateParams = array();
   foreach ($matches[0] as $iterator => $match) {
      $text = str_replace($match, '%'.$iterator, $text);
      $translateParams[] = $helper->render($match);
   }
   array_unshift($translateParams, $text);
   return call_user_func_array('translateText', $translateParams);
}

For basic usage, it works nicely, but if I try to translate something inside a translation, like this:

 {{# func.Translate }} Translate this, and {{# func.Translate }} translate this separately {{/ func.Translate }} {{/ func.Translate }}

i am getting errors, because my regular expression matcher, will match each inner mustache tag separately.

It matches: {{# func.Translate }}, and {{/ func.Translate }} instead of matching {{# func.Translate }} translate this separately {{/ func.Translate }}.

My problem is that I am a novice when it comes to regular expressions, and I can't figure out how could I match with a single preg_match both the simple mustache expressions ({{variable}}) and the more complex ones like in the example. Could anyone help me please?

Adam Baranyai
  • 3,635
  • 3
  • 29
  • 68
  • I think you need something like `/{{#\s*([^{}]*?)\s*}}((?:(?!{{).)*?){{\/\s*\1\s*}}/s`, see https://regex101.com/r/Z5p3Yb/1/ – Wiktor Stribiżew Feb 06 '20 at 21:55
  • Unfortunately, that doesn't match for: `{{# func.Translate }} Translate this, and {{# func.Translate }} translate this separately {{/ func.Translate }} {{name}} {{bool}} {{/ func.Translate }}` the second `{{name}}` and `{{bool}}` strings. :( – Adam Baranyai Feb 06 '20 at 21:59
  • 1
    No, it is not necessary because you should run the regex replacement until no match (in a loop, `while (preg_match($thePatternAbove, $text)) {...}`). Once you replace the innermost part, you will be able to match the outer one. – Wiktor Stribiżew Feb 06 '20 at 22:02
  • That's a good idea, but it still doesn't match this pattern (in fact, it doesn't match anything in this pattern): `{{# func.Translate }} Translate this, and {{# func.Translate }} translate this {{name}} separately {{/ func.Translate }} {{/ func.Translate }}` – Adam Baranyai Feb 06 '20 at 22:07
  • Just make sure the pattern matches, I do not quite get the requirements. – Wiktor Stribiżew Feb 06 '20 at 22:09
  • So, what are the requirements? Try https://regex101.com/r/Z5p3Yb/2 – Wiktor Stribiżew Feb 07 '20 at 20:06
  • Please precise what exact output you want to get – Wiktor Stribiżew Feb 10 '20 at 07:29

0 Answers0