2011-01-15 23 views
9

Zacząłem moją aplikację PHP z całym tekstem w języku niemieckim, potem użyłem gettext, aby wyodrębnić wszystkie ciągi i przetłumaczyć je na angielski.
Tak, teraz mam plik .po ze wszystkimi msgids w języku niemieckim i msgstrs w języku angielskim. Chcę je przełączać, tak, że mój kod źródłowy zawiera angielskiego jako msgid z dwóch głównych powodów:Przełącz tekst przetłumaczony na gettext z oryginalnym językiem

  1. Więcej tłumacze znają angielskiego, więc jest to tylko właściwe im służyć plik z msgid po angielsku. I może zawsze przełączać plik, zanim go podaję i po otrzymaniu go, ale naaah.
  2. Pomoże mi napisać angielską nazwę obiektu & w nazwach funkcji i komentarzach, jeśli tekst treści był również angielski. Chciałbym to zrobić, więc projekt jest bardziej otwarty dla innych współpracowników Open Source (częściej znają angielski niż niemiecki).

mogę to zrobić ręcznie i jest to rodzaj zadania, gdzie przewidujemy zajmie mi więcej czasu na pisanie zautomatyzowaną procedurę dla niego (bo jestem bardzo złe ze skryptów powłoki) niż zrobić ręcznie. Ale przewiduję też, że każdy minutę pogardza ​​każdą minutą ręcznego komputera pracy (czuje się jak oksymoron, prawda?) Jak zawsze.

Czy ktoś już to zrobił? Pomyślałem, że będzie to powszechny problem, ale nie mogłem nic znaleźć. Wielkie dzięki.

Sample Problem:

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

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

pomyślałem, że zawężenie problemu w dół. Przełącznik w .po akt nie jest kwestia oczywiście, to jest tak proste, jak

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

Problemem dla mnie jest rutynowe, że przeszukuje moje pliki folderze projektu dla _('$msgid') i substytutów _('msgstr') podczas parsowania .po- plik (który prawdopodobnie nie jest nawet najbardziej elegancki, po tym jak wszystkie pliki .po zawierają komentarze zawierające wszystkie ścieżki plików, w których występuje msgid).


Po fooling around z odpowiedzią akirk trochę wpadłem na kolejne problemy.

  1. Bo mam mieszankę _('xxx') i _("xxx") połączeń, muszę być ostrożny (ONZ) ucieczkę.
    • Podwójne cudzysłowy "w msgid i msgstrs być Niecytowany, ale ukośniki nie mogą być usunięte, ponieważ może się okazać, że cudzysłów również uciekł w PHP
    • Pojedyncze cudzysłowy muszą być uciekł, gdy "zamieniono je na PHP, ale potem trzeba je również zmienić w pliku .po. Na szczęście pojedyncze cytaty pojawiają się tylko w tekście angielskim.
  2. msgid i msgstrs może mieć wiele wierszy, wtedy wyglądać następująco
    msgid = ""
    "line 1\n"
    "line 2\n"
    msgstr = ""
    "line 1\n"
    "line 2\n"
  3. mnogiej są oczywiście pominąć w tej chwili, ale w moim przypadku to nie problem
  4. Poedit chce usunąć ciągi jako przestarzałe, które sprawiają wrażenie przełączanych i nie mam pojęcia, dlaczego tak się dzieje w (wielu) przypadkach.

Muszę przestać nad tym pracować na dziś wieczór. Wciąż wydaje się, że użycie parsera zamiast RegExps nie byłoby przesadą.

+0

Trudno byłoby nie tylko zmienić wpisy w plikach gettext, ale również zamienić wszystkie ciągi znaków w kodzie. – markus

+0

@tharkun: Tak, oczywiście, to jest to, co muszę zrobić, ale to nie wydaje mi się tak trudne. Myślę, że mógłbym to zrobić za pomocą łańcucha PHP, ale nie z powłoką. w najprostszy sposób wystarczy przeanalizować (lub wyszukać) plik .po dla msgids i strs, a następnie wyszukać i zamienić wszystkie pliki w folderze dla tego ciągu. Włączyłem przełącznik w słupku, aby zmniejszyć problem. – Ruben

+0

Myślę, że jesteś na dobrej drodze. Sztuką byłoby upewnić się, że regEx, którego używasz, nieumyślnie zmienia rzeczywiste źródło. Nie zapominaj, że regEx musiałby również obsłużyć pojedyncze i podwójne cudzysłów do '_ (...)'. Powodzenia. –

Odpowiedz

1

Zobacz http://code.activestate.com/recipes/475109-regular-expression-for-python-string-literals/ dobrego Pythona oparte wyrażenia regularnego do znalezienia literały ciągów, biorąc pod uwagę ucieczki. Chociaż jest to python, może to być całkiem dobre dla ciągów wielowierszowych i innych narożnych przypadków.

Zapoznaj się z http://docs.translatehouse.org/projects/translate-toolkit/en/latest/commands/poswap.html, aby uzyskać gotowy, gotowy do użycia program do wymiany języka podstawowego dla plików .po.

Na przykład poniższy wiersz polecenia zamieni niemieckie tłumaczenie na hiszpańskie na hiszpańskie. Musisz tylko upewnić się, że nowy język bazowa (po angielsku) jest w 100% przetłumaczone przed konwersją wyjściowego:

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

I wreszcie zamienić angielski plik po niemieckich pliku PO, użyj swappo: http://manpages.ubuntu.com/manpages/hardy/man1/swappo.1.html

Po zamieniając pliki, może być wymagane ręczne polerowanie plików wynikowych. Na przykład nagłówki mogą zostać zerwane i mogą wystąpić duplikaty tekstów.

+0

Umieściłem skrypt Pythona do zamiany źródeł/języków docelowych w plikach PO. Może to być przydatne w tym przypadku: http://mola.io/2013/09/17/swapping-languages-in-gettext-po-file/ – smola

1

Więc jeśli dobrze cię rozumiem, chciałbyś zastąpić wszystkie niemieckie połączenia tekstowe z angielskimi. Aby zastąpić zawartość w katalogu, coś takiego może działać.

$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

Tak, ale nawet jeśli oczywiście mogę podać plik po jako ciąg, muszę wyszukać i zastąpić __ katalog plików php__, a nie ciąg znaków. Chciałbym też w końcu wiedzieć, których msgstrów nie można znaleźć (byłoby to wywołanie funkcji dla form liczby mnogiej i symboli zastępczych: tak mało, żebym mógł je wykonać ręcznie). Miałem nadzieję, że sam parser gettext może być jakoś użyty, w końcu robi coś bardzo podobnego (parsowanie plików php i znajdowanie msgids w określonych wywołaniach funkcji). – Ruben

+0

Nie jestem świadomy narzędzia w dystrybucji gettext, będziesz musiał to zrobić ręcznie (co nie jest nudne). Zmieniłem kod, aby to odzwierciedlić. – akirk

+0

Oszukałem twój skrypt nieco http://pastebin.com/J7ipM1fy, aby łatwiej zobaczyć, które napisy zostały znalezione. Radzenie sobie z cudzysłowami i wieloliniowymi ciągami nie jest łatwe, a ja zaktualizuję moje pytanie, aby to odzwierciedlić. – Ruben

5

zbudowałem na odpowiedź akirk i chciał zachować to, co wymyśliłem jako odpowiedź tutaj, na wypadek, gdyby ktoś ma ten sam problem. To nie jest rekurencyjne, ale może łatwo ulec zmianie. Możesz komentować z ulepszeniami, będę oglądać i edytować ten post.

$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

Świetnie! Uratowałeś mój dzień :) –