How does gettext handle dynamic content?

2019-01-22 21:56发布

问题:

In php (or maybe gettext in general), what does gettext do when it sees a variable to dynamic content?

I have 2 cases in mind.

1) Let's say I have <?=$user1?> poked John <?=$user2?>. Maybe in some language the order of the words is different. How does gettext handle that? (no, I'm not building facebook, that was just an example)

2) Let's say I store some categories in a database. They rarely, but they are store in a database. What would happen if I do <?php echo gettext($data['name']); ?> ? I would like the translators to translate those category names too, but does it have to be done in the database itself?

Thanks

回答1:

Your best option is to use spritf() function. Then you would use printf notation to handle dynamic content in your strings. Here is a function I found on here a while ago to handle this easily for you:

function translate()
{
    $args = func_get_args();
    $num = func_num_args();
    $args[0] = gettext($args[0]);

    if($num <= 1)
      return $args[0];

    return call_user_func_array('sprintf', $args);

}

Now for example 1, you would want to change the string to:

%s poked %s

Which you would input into the translate() function like this:

<?php echo translate('%s poked %s', $user1, $user2); ?>

You would parse out all translate() functions with poEdit. and then translate the string "%s poked %s" into whatever language you wanted, without modifying the %s string placeholders. Those would get replace upon output by the translate() function with user1 and user2 respectively. You can read more on sprintf() in the PHP Manual for more advanced usages.

For issue #2. You would need to create a static file which poEdit could parse containing the category names. For example "misctranslations.php":

<?php

_('Cars');
_('Trains');
_('Airplanes');

Then have poEdit parse misctranslations.php. You would then be able to output the category name translation using <?php echo gettext($data['name']); ?>



回答2:

To build a little on what Mark said... the only problem with the above solution is that the static list must be always maintained by hand and if you add a new string before all the others or you completely change an existing one, the soft you use for translating might confuse the new strings and you could lose some translations.

I'm actually writing an article about this (too little time to finish it anytime soon!) but my proposed answer goes something like this:

Gettext allows you to store the line number that the string appears in the code inside the .po file. If you change the string entirely, the .po editor will know that the string is not new but it is an old one (thanks to the line number).

My solution to this is to write a script that reads the database and creates a static file with all the gettext strings. The big difference to Mark's solution is to have the primary key (let's call it ID) on the database match the line number in the new file. In that case, if you completely change one original translation, the lines are still the same and your translator soft will recognize the strings.

Of course there might be newer and more intelligent .po editors out there but at least if yours is giving you trouble with newer strings then this will solve them.

My 2 cents.



回答3:

If you have somewhere in your code: <?=sprintf(_('%s poked %s'), $user1, $user2)?> and one of your languages needs to swap the arguments it is very simple. Simply translate your code like this: msgid "%s poked %s" msgstr "%2$s translation_of_poked %1$s"



回答4:

@Julian

I think your approach would not work well in the practice. Imagine, that you move some function across the code. The line number will be different, also the file name could differ.

I think the only intelligent way to manage the changing of translation ids would be to try to find similar ids in your .po-file. The editor could show a suggestion for merging the new translation text with the existing one, if they are very similar and there is no translation string in the saved line number in your code.