Search code examples
phplocalizationgettextphp-gettext

PHP: Localizing string containing variables


So far I had no problems localizing strings with gettext, not unless strings contain variables. I followed the steps from this excellent tutorial, but whenever I try to apply this on this function, I'm running into trouble.

/**
 *    @ http://us.php.net/manual/en/function.time.php#71342
 */
function time_ago($timestamp, $recursive = 0)
{
    $current_time = time();
    $difference = $current_time - $timestamp;
    $periods = array("second", "minute", "hour", "day", "week", "month", "year", "decade");
    $lengths = array(1, 60, 3600, 86400, 604800, 2630880, 31570560, 315705600);
    for ($val = sizeof($lengths) - 1; ($val >= 0) && (($number = $difference / $lengths[$val]) <= 1); $val--);
    if ($val < 0) $val = 0;
    $new_time = $current_time - ($difference % $lengths[$val]);
    $number = floor($number);
    if($number != 1)
    {
        $periods[$val] .= "s";
    }
    $text = sprintf(_("%d %s ago"), $number, $periods[$val]);   

    if (($recursive == 1) && ($val >= 1) && (($current_time - $new_time) > 0))
    {
        $text .= time_ago($new_time);
    }
    return $text;
}

The strings from my messages.po look like this:

msgid "%d second ago"
msgid_plural "%d seconds ago"
msgstr[0] "Vor einer Sekunde"
msgstr[1] "Vor %d Sekunden"    

msgid "%d minute ago"
msgid_plural "%d minutes ago"
msgstr[0] "Vor einer Minute"
msgstr[1] "Vor %d Minuten"    

msgid "%d hour ago"
msgid_plural "%d hours ago"
msgstr[0] "Vor einer Stunde"
msgstr[1] "Vor %d Stunden"

# and so forth…

Unfortunately, these strings don't get translated, whereas all others (without variables) work perfectly. What am I doing wrong here?


Solution

  • I think you have a little typo:

    $text = sprintf(_("%d %s ago", $number, $periods[$val]));   
    

    .... should be:

    $text = sprintf(_("%d %s ago"), $number, $periods[$val]);  
    

    Otherwise you are trying to find 3 days ago in the catalogue.


    If you have this:

    _("%d %s ago")
    

    ... the string ID must match exactly that:

    msgid "%d %s ago"
    

    You appear to have split that in three different strings which (from the gettext point of view) are not related to this:

    msgid "%d second ago"
    msgid "%d minute ago"
    msgid "%d hour ago"
    

    To be able to use those IDs you need to pass that exact text to _():

    sprintf(_(sprintf('%%d %s ago', $periods[$val])), $number)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
              // This itself prints: %d days ago
    

    A little gotcha, though: if you issue calls to _() using variables, you won't be able to update catalogues automatically and you'll have to add and remove strings manually.