array ( * 'msgid' => '', * 'msgstr' => array ( * 0 => 'Project-Id-Version: ...', * ), * ), * 'string for translation 1' => array ( * 'msgid' => 'string for translation 1', * 'msgstr' => array ( * 0 => 'translated string 1', * ), * ), * 'string for translation 2' => array ( * 'msgid' => 'string for translation 2', * 'msgstr' => array ( * 0 => 'translated string 2', * 1 => 'translated string 2 but different context', * 2 => 'another translated string 2 with different context', * ), * 'msgctxt' => array ( * 1 => 'context explanation for msgstr[1]', * 2 => 'context explanation for msgstr[2]', * ), * ), * 'string for translation 3' => array ( * 'msgid' => 'string for translation 3', * 'msgid_plural' => 'plural string for translation 3', * 'msgstr' => array ( * 0 => array ( * 0 => 'translated string 3 for nplurals 0', * 1 => 'translated string 3 for nplurals 1', * 2 => 'translated string 3 for nplurals 2', * ), * ), * ), * ); * **************************************************************************************** * * based on php.mo 0.1 by Joss Crowcroft (http://www.josscrowcroft.com) * which is * Based on php-msgfmt by Matthias Bauer (Copyright © 2007), a command-line PHP tool * for converting .po files to .mo. * (http://wordpress-soc-2007.googlecode.com/svn/trunk/moeffju/php-msgfmt/msgfmt.php) * * License: GPL v3 http://www.opensource.org/licenses/gpl-3.0.html */ function phpmo_clean_helper($x) { if (is_array($x)) { foreach ($x as $k => $v) { $x[$k] = phpmo_clean_helper($v); } } else { if ($x[0] == '"') $x = substr($x, 1, -1); $x = str_replace("\"\n\"", '', $x); $x = str_replace('$', '\\$', $x); } return $x; } /* Parse gettext .po files. */ /* @link http://www.gnu.org/software/gettext/manual/gettext.html#PO-Files */ function phpmo_parse_po_file($in) { // read .po file $fh = @fopen($in, 'r'); if ($fh === false) { // Could not open file resource return false; } // results array $hash = array (); // temporary array $temp = array (); // state $state = null; $fuzzy = false; // iterate over lines while(($line = fgets($fh, 65536)) !== false) { $line = trim($line); if ($line === '') continue; $array_of_splited_string = preg_split('/\s/', $line, 2); $key = $array_of_splited_string[0]; $data = (isset($array_of_splited_string[1]) ? $array_of_splited_string[1] : ''); switch ($key) { case '#,' : // flag... case '#' : // translator-comments case '#.' : // extracted-comments case '#:' : // reference... case '#|' : // msgid previous-untranslated-string case '#~' : // commented-unused-string // start a new entry if (sizeof($temp) && array_key_exists('msgid', $temp) && array_key_exists('msgstr', $temp)) { if (!$fuzzy) $hash[] = $temp; $temp = array (); $state = null; $fuzzy = false; } if ($key == '#,') $fuzzy = in_array('fuzzy', preg_split('/,\s*/', $data)); break; case 'msgctxt' : // context case 'msgid' : // untranslated-string case 'msgid_plural' : // untranslated-string-plural $state = $key; // store previous entry if it exists if (sizeof($temp) && array_key_exists('msgid', $temp) && array_key_exists('msgstr', $temp)) { if (!$fuzzy) $hash[] = $temp; $temp = array (); $fuzzy = false; } if ($key == 'msgctxt') { if (array_key_exists('msgstr', $temp)) { $msgctxt_index = count($temp['msgstr']); } else { $msgctxt_index = 0; } $temp['msgctxt'][$msgctxt_index] = $data; } else { $temp[$state] = $data; } break; case 'msgstr' : // translated-string $state = 'msgstr'; $temp[$state][] = $data; break; default : if (strpos($key, 'msgstr[') !== FALSE) { // translated-string-case-n $state = 'msgstr'; $temp[$state][] = $data; } else { // continued lines switch ($state) { case 'msgid' : case 'msgid_plural' : $temp[$state] .= "\n" . $line; break; case 'msgctxt' : case 'msgstr' : $temp[$state][sizeof($temp[$state]) - 1] .= "\n" . $line; break; default : // parse error fclose($fh); return FALSE; } } break; } } fclose($fh); // add final entry if ($state == 'msgstr') if (!$fuzzy) $hash[] = $temp; // Cleanup data, merge multiline entries, reindex hash for ksort $temp = $hash; $hash = array (); foreach ($temp as $entry) { foreach ($entry as & $v) { $v = phpmo_clean_helper($v); if ($v === FALSE) { // parse error return FALSE; } } // if there's already same msgid we need to store it there if (array_key_exists($entry['msgid'], $hash)) { $index = count($hash[$entry['msgid']]['msgstr']); $hash[$entry['msgid']]['msgstr'][$index] = $entry['msgstr'][0]; // is different msgctxt present also? if (array_key_exists('msgctxt', $entry)) { $hash[$entry['msgid']]['msgctxt'][$index] = $entry['msgctxt'][0]; } } else { // if msgid_plural exists we need to store msgstr to subarray for proper counting of l10n completion if (array_key_exists('msgid_plural', $entry)) { $msgstr_plural = $entry['msgstr']; $entry['msgstr'] = array(); $entry['msgstr'][] = $msgstr_plural; } $hash[$entry['msgid']] = $entry; } } return $hash; }