frietkot
frietkot

Reputation: 911

Parsing template language in php

Some days ago I came across jquery.i18n from the wikimedia foundation that enables to translate strings like Welcome, $1 and Found $1 {{PLURAL:$1|result|results}}.

I'd like to recreate that functionality in PHP just for educational purposes.

I was able to create a parser that parses strings like Welcome, $1 but now I'm looking to recreate the second functionality Found $1 {{METHOD:$1|parameters|...}} but I cannot figure out how to create some functionality to do that.

Can anyone push me into the right direction? I've already looked at the sourcecode of the jquery.i18n library and I am not looking to implement another existing translation library, just create one on my own.

This is what I've got for the simple argument parsing function:

public function parse($message, $replacements)
{
    if (strrpos($message, '{{') === false) {
        return $this->simpleParse($message, $replacements);
    }
}

protected function simpleParse($message, $replacements)
{
    return preg_replace_callback('/\$(\d+)/', function ($match) use ($replacements) {
        $key = $match[1] - 1;
        if (isset($replacements[$key])) {
            return $replacements[$key];
        }

        return $match[0];
    }, $message);
}

Upvotes: 0

Views: 103

Answers (1)

georg
georg

Reputation: 214949

This seems to work well:

function parse($msg, $args) {
    return preg_replace_callback('~{{(\w+):(.+?)}}|\$(\d+)~', function($m) use($args) {
        if(strlen($m[1]))
            return parse_func(
                strtolower($m[1]),
                explode('|', $m[2]),
                $args);
        return $args[$m[3] - 1];
    }, $msg);
}

function parse_func($name, $params, $args) {
    foreach($params as &$p) {
        if(preg_match('~^\$(\d+)$~', $p, $m))
            $p = $args[$m[1] - 1];
    }
    return call_user_func_array("handle_$name", $params);
}

function handle_plural($value, $sing, $plu) {
    return intval($value) > 1 ? $plu : $sing;
}

// works!

$msg = "Found $1 {{PLURAL:$1|mouse|mice}} and $2 {{PLURAL:$2|apple|apples}}\n";

print parse($msg, [1, 5]);
print parse($msg, [6, 1]);

The idea is to replace everything (dollars and braces) at once and take an appropriate action in the replacement function. You can add more 'methods' like "plural" by defining additional handle_xxx functions.

Upvotes: 1

Related Questions