Переключить перевод текста gettext с языка оригинала - PullRequest
9 голосов
/ 15 января 2011

Я запустил свое PHP-приложение со всем текстом на немецком языке, затем использовал gettext, чтобы извлечь все строки и перевести их на английский.
Итак, теперь у меня есть .po файл со всеми сообщениями на немецком языке и сообщениями на английском языке. Я хочу переключить их, чтобы мой исходный код содержал английский как msgids по двум основным причинам:

  1. Другие переводчики будут знать английский, поэтому целесообразно предоставить им файл с msgids на английском языке. Я мог бы всегда переключать файл, прежде чем выдать его и после того, как я его получу, но наах.
  2. Это помогло бы мне написать английские имена объектов и функций и комментарии, если бы текст контента был также английским. Я бы хотел сделать это, чтобы проект был более открыт для других сотрудников Open Source (с большей вероятностью знает английский, чем немецкий).

Я мог бы сделать это вручную, и это та задача, в которой, как я ожидаю, у меня будет больше времени, чтобы написать автоматизированную подпрограмму для нее (потому что я очень плох с скриптами оболочки), чем сделать это от руки. Но я также ожидаю презирать каждую минуту ручного компьютерного труда (похоже на оксюморон, верно?), Как я всегда делаю.

Кто-то делал это раньше? Я подумал, что это будет распространенная проблема, но не смог ничего найти. Большое спасибо вперед.

Пример задачи:

<title><?=_('Routinen')?></title>

#: /users/ruben/sites/v/routinen.php:43
msgid "Routinen"
msgstr "Routines"

Я думал, что смогу сузить проблему. Переключатель в .po-файле, конечно, не проблема, он так же прост, как

preg_replace('/msgid "(.+)"\nmsgstr "(.+)"/', '/msgid "$2"\nmsgstr "$1"/', $str);

Проблема для меня заключается в том, что процедура ищет в файлах папки моего проекта _('$msgid') и заменяет _('msgstr') при анализе .po-файла (что, вероятно, даже не самый элегантный способ, после всего .po-файла). содержит комментарии, которые содержат все пути к файлам, где встречается сообщение).


После дурачиться с небольшим ответом Акирка я столкнулся с еще некоторыми проблемами.

  1. Поскольку у меня есть смесь _('xxx') и _("xxx") вызовов, я должен быть осторожен с (не) побегом.
    • Двойные кавычки "в msgid и msgstrs должны быть не экранированы, но косые черты не могут быть удалены, потому что может быть, что двойная кавычка также была экранирована в PHP
    • Одиночные кавычки должны быть экранированы при их замене на PHP, но затем они также должны быть изменены в .po-файле. К счастью для меня, одинарные кавычки появляются только в английском тексте.
  2. msgid и msgstrs могут иметь несколько строк, тогда они выглядят так
    msgid = ""
    "line 1\n"
    "line 2\n"
    msgstr = ""
    "line 1\n"
    "line 2\n"
  3. Формы множественного числа, конечно, в данный момент пропускаются, но в моем случае это не проблема
  4. poedit хочет удалить устаревшие строки, которые кажутся успешно переключенными, и я понятия не имею, почему это происходит во (многих) случаях.

Мне придется перестать работать над этим на сегодня. Тем не менее кажется, что использование парсера вместо RegExps не будет излишним.

Ответы [ 3 ]

5 голосов
/ 18 января 2011

Я опирался на ответ Акирка и хотел сохранить то, что придумал в качестве ответа, на случай, если у кого-то возникнет такая же проблема. Это не рекурсивно, но это может легко измениться конечно. Не стесняйтесь комментировать с улучшениями, я буду смотреть и редактировать этот пост.

$po = file_get_contents("locale/en_GB/LC_MESSAGES/messages.po");

$translations = array(); // german => english
$rawmsgids = array(); // find later
$msgidhits = array(); // record success
$msgstrs = array(); // find later

preg_match_all('/msgid "(.+)"\nmsgstr "(.+)"/', $po, $matches, PREG_SET_ORDER);

foreach ($matches as $match) {
    $german = str_replace('\"','"',$match[1]); // unescape double quotes (could misfire if you escaped double quotes in PHP _("<a href=\"bla\">bla</a>") but in my case that was one case versus many)
    $english = str_replace('\"','"',$match[2]);


    $en_sq_e = str_replace("'","\'",$english); // escape single quotes

    $translations['_(\''. $german . '\''] = '_(\'' . $en_sq_e . '\'';
    $rawmsgids['_(\''. $german . '\''] = $match[1]; // find raw msgid with searchstr as key

    $translations['_("'. $match[1] . '"'] = '_("' . $match[2] . '"';
    $rawmsgids['_("'. $match[1] . '"'] = $match[1];

    $translations['__(\''. $german . '\''] = '__(\'' . $en_sq_e . '\'';
    $rawmsgids['__(\''. $german . '\''] = $match[1];

    $translations['__("'. $match[1] . '"'] = '__("' . $match[2] . '"';
    $rawmsgids['__("'. $match[1] . '"'] = $match[1];

    $msgstrs[$match[1]] = $match[2]; // msgid => msgstr
}


foreach (glob("*.php") as $file) {
    $code = file_get_contents($file);

    $filehits = 0; // how many replacements per file

    foreach($translations AS $msgid => $msgstr) {
        $hits = 0;
        $code = str_replace($msgid,$msgstr,$code,$hits);
        $filehits += $hits;

        if($hits!=0) $msgidhits[$rawmsgids[$msgid]] = 1; // this serves to record if the msgid was found in at least one incarnation
        elseif(!isset($msgidhits[$rawmsgids[$msgid]])) $msgidhits[$rawmsgids[$msgid]] = 0;
    }
    // file_put_contents($file, $code); // be careful to test this first before doing the actual replace (and do use a version control system!) 
    echo "$file : $filehits <br>"; 
    echo $code;
}
/* debug */ 
$found = array_keys($msgidhits, 1, true);
foreach($found AS $mid) echo $mid . " => " . $msgstrs[$mid] . "\n\n";

echo "Not Found: <br>";
$notfound = array_keys($msgidhits, 0, true);
foreach($notfound AS $mid) echo $mid . " => " . $msgstrs[$mid] . "\n\n";

/*
following steps are still needed:
    * convert plurals (ngettext)
    * convert multi-line msgids and msgstrs (format mentioned in question)
    * resolve uniqueness conflict (msgids are unique, msgstrs are not), so you may have duplicate msgids (poedit finds these)
*/
1 голос
/ 08 апреля 2011

См. http://code.activestate.com/recipes/475109-regular-expression-for-python-string-literals/ для хорошего регулярного выражения на основе Python для поиска строковых литералов с учетом экранирования.Несмотря на то, что это python, это может быть неплохо для многострочных строк и других угловых случаев.

См. http://docs.translatehouse.org/projects/translate-toolkit/en/latest/commands/poswap.html для готового, готового к замене базового языка для файлов .po.

Например, следующая командная строка преобразует испанский перевод на основе немецкого языка в испанский перевод на основе английского языка.Вам просто нужно убедиться, что ваш новый базовый язык (английский) переведен на 100% перед началом преобразования:

poswap -i de-en.po -t de-es.po -o en-es.po

И, наконец, чтобы поменять английский po-файл на немецкий po-файл, используйте swappo: http://manpages.ubuntu.com/manpages/hardy/man1/swappo.1.html

После замены файлов может потребоваться некоторая ручная полировка результирующих файлов.Например, заголовки могут быть повреждены, и могут появиться дубликаты текстов.

1 голос
/ 17 января 2011

Так что, если я вас правильно понял, вы хотели бы заменить все вызовы gettext на немецком языке на английские. Чтобы заменить содержимое в каталоге, что-то вроде этого может работать.

$po = file_get_contents("translation.pot");
$translations = array(); // german => english
preg_match_all('/msgid "(.+)"\nmsgstr "(.+)"/', $po, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
    $translations['_("'. $match[1] . '")'] = '_("' . $match[2] . '")';
    $translations['_(\''. $match[1] . '\')'] = '_(\'' . $match[2] . '\')';
}
foreach (glob("*.php") as $file) {
    $code = file_get_contents($file);
    $code = str_replace(array_keys($translations), array_values($translations), $code);
    //file_put_contents($file, $code);
    echo $code; // be careful to test this first before doing the actual replace (and do use a version control system!)
}
...