2011-01-15 3 views
9

Ich habe meine PHP-Anwendung mit allem Text auf Deutsch gestartet, dann habe ich gettext benutzt, um alle Strings zu extrahieren und ins Englische zu übersetzen.
So, jetzt habe ich eine .po-Datei mit allen msgids in Deutsch und msgstrs in Englisch. Ich mag, dass sie zu wechseln, so dass mein Quellcode, um das Englisch als msgids aus zwei Hauptgründen enthält:Switch gettext übersetzte Sprache mit Originalsprache

  1. Mehr Übersetzer wissen Englisch, so ist es nur angemessen, sie eine Datei mit msgids aufzuzutischen auf Englisch. Ich kann immer die Datei wechseln, bevor ich es gebe und nachdem ich es erhalte, aber naaah.
  2. Es würde mir helfen, Englisch Objekt & Funktionsnamen und Kommentare zu schreiben, wenn der Inhalt Text auch Englisch war. Ich würde das gerne machen, also ist das Projekt offen für andere Open-Source-Mitarbeiter (eher Englisch als Deutsch).

ich dies manuell tun könnte, und das ist die Art von Aufgabe, wo ich es zu antizipieren mir mehr Zeit nehmen, eine automatisierte Routine für sie zu schreiben (weil ich sehr schlecht mit Shell-Skripten bin), als es zu tun von Hand. Aber ich erwarte auch, jede Minute manuelle Computerarbeit zu verachten (fühlt sich an wie ein Oxymoron, richtig?), Wie ich es immer tue.

Hat jemand das schon mal gemacht? Ich dachte, das wäre ein häufiges Problem, konnte aber nichts finden. Vielen Dank im Voraus.

Probe Problem:

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

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

Ich dachte, ich das Problem eingrenzen würde. Der Schalter in der .po-Datei ist kein Problem natürlich, es ist so einfach wie

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

Das Problem für mich ist die Routine, die meine Projektordner Dateien für _('$msgid') und Ersatzsucht _('msgstr') während der .po- Parsen Datei (was wahrscheinlich nicht einmal der eleganteste Weg ist, nachdem die .po-Datei Kommentare enthält, die alle Dateipfade enthalten, wo die msgid auftritt).


Nach fooling around mit Antwort des akirk ein wenig, ich lief in einige Probleme mehr.

  1. Weil ich eine Mischung aus _('xxx') und _("xxx") Anrufe haben, muss ich über (un) vorsichtig sein, zu entkommen.
    • doppelte Anführungszeichen "in msgids und msgstrs haben unescaped sein, aber die Schrägstriche gestrippt können nicht sein, weil es, dass die doppelten Anführungszeichen auch in PHP
    • Einfache Anführungszeichen, wenn entwertet werden müssen entgangen waren sein kann sie In PHP werden sie ersetzt, aber dann müssen sie auch in der .po-Datei geändert werden. Glücklicherweise erscheinen einfache Anführungszeichen nur in englischem Text.
  2. msgids und msgstrs mehrere Zeilen haben kann, dann sehen sie aus wie dieses
    msgid = ""
    "line 1\n"
    "line 2\n"
    msgstr = ""
    "line 1\n"
    "line 2\n"
  3. Pluralformen sind natürlich im Moment übersprungen, aber in meinem Fall ist das kein Problem
  4. poedit möchte Strings als veraltet entfernen, die erfolgreich geschaltet scheinen und ich habe keine Ahnung, warum dies in (vielen) Fällen passiert.

Ich muss aufhören für heute Nacht daran zu arbeiten. Dennoch scheint es, dass die Verwendung des Parsers anstelle von RegExps nicht übertrieben ist.

+0

knifflig, nicht nur müssten Sie die Einträge in den gettext-Dateien wechseln, müssten Sie auch alle Zeichenfolgen in Ihrem Code ersetzen. – markus

+0

@tharkun: Ja natürlich, das ist was ich tun müsste, aber das scheint mir nicht so schwierig zu sein. Ich denke, ich könnte es mit einer PHP-Zeichenfolge tun, aber nicht mit der Shell. auf die einfachste Weise würde man die .po-Datei einfach nach msgids und strs durchsuchen (oder durchsuchen) und dann alle Dateien in einem Ordner nach dieser Zeichenfolge suchen und ersetzen. Ich habe den Schalter in die Post eingefügt, um das Problem einzugrenzen. – Ruben

+0

Ich denke du bist hier auf dem richtigen Weg. Der Trick wäre, sicherzustellen, dass die RegEx, die Sie verwenden, nicht versehentlich die tatsächliche Quelle ändert. Vergessen Sie nicht, dass regEx auch einfache und doppelte Anführungszeichen für '_ (...)' verarbeiten muss. Viel Glück. –

Antwort

1

Siehe http://code.activestate.com/recipes/475109-regular-expression-for-python-string-literals/ für einen guten Python-basierte regulären Ausdruck für Stringliterale finden, Fluchten zu berücksichtigen. Obwohl es sich um Python handelt, könnte dies für mehrzeilige Strings und andere Eckfälle recht gut sein.

Siehe http://docs.translatehouse.org/projects/translate-toolkit/en/latest/commands/poswap.html für einen gebrauchsfertigen Basissprachen-Swapper für .po-Dateien.

Zum Beispiel konvertiert die folgende Befehlszeile deutsche Übersetzung ins Spanische. Sie müssen nur sicherstellen, dass Ihre neue Basissprache (Englisch) 100% vor dem Start Umwandlung übersetzt ist:

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

Und schließlich Englisch po-Datei auf Deutsch po-Datei verwenden swappo zu tauschen: http://manpages.ubuntu.com/manpages/hardy/man1/swappo.1.html

Nach Austauschen von Dateien ist möglicherweise ein manuelles Polieren der resultierenden Dateien erforderlich. Zum Beispiel könnten Kopfzeilen beschädigt sein und einige doppelte Texte könnten auftreten.

+0

Ich habe ein Python-Skript zum Tauschen von Quell-/Ziel-LAN-Dateien in PO-Dateien gepostet. Dies könnte für diesen Fall nützlich sein: http://mola.io/2013/09/17/swapping-languages-in-gettext-po-file/ – smola

1

Also wenn ich Sie richtig verstehe, möchten Sie alle deutschen gettext Anrufe durch englische ersetzen. Um den Inhalt im Verzeichnis zu ersetzen, könnte so etwas funktionieren.

$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!) 
} 
+0

Ja, aber obwohl ich natürlich die Po-Datei als String angeben kann, muss ich ein __Verzeichnis von PHP-Dateien suchen und ersetzen, keine Zeichenfolge. Ich möchte auch am Ende wissen, welche msgids nicht gefunden werden konnten (das wären Funktionsaufrufe für Pluralformen und Platzhalter: so wenige, dass ich sie von Hand machen könnte). Ich hatte gehofft, dass der gettext-parser selbst irgendwie benutzt werden könnte, immerhin macht er schon etwas sehr ähnliches (parse php-dateien und finde msgids in spezifizierten Funktionsaufrufen). – Ruben

+0

Ich bin mir nicht bewusst, ein Werkzeug in der gettext-Verteilung, Sie müssen es von Hand tun (was nicht so langweilig ist). Ich habe meinen Code geändert, um dies zu berücksichtigen. – akirk

+0

Ich habe mit deinem Skript ein bisschen http://pastebin.com/J7ipM1fy getäuscht, um leichter zu sehen, welche Strings gefunden wurden. Der Umgang mit Anführungszeichen und mehrzeiligen Strings ist jedoch nicht trivial und ich werde meine Frage aktualisieren, um das zu berücksichtigen. – Ruben

5

Ich baute auf akirk's Antwort auf und wollte das, was mir einfiel, als Antwort hier aufbewahren, falls jemand das gleiche Problem hat. Dies ist nicht rekursiv, aber das könnte natürlich leicht ändern. Fühlen Sie sich frei, mit Verbesserungen zu kommentieren, ich werde diesen Beitrag ansehen und bearbeiten.

$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

Großartig! Du hast meinen Tag gerettet :) –