+ /**
+ * @param string $filename
+ * @return boolean
+ */
+ function import_from_file($filename) {
+ $f = fopen($filename, 'r');
+ if (!$f) return false;
+ $lineno = 0;
+ while (true) {
+ $res = $this->read_entry($f, $lineno);
+ if (!$res) break;
+ if ($res['entry']->singular == '') {
+ $this->set_headers($this->make_headers($res['entry']->translations[0]));
+ } else {
+ $this->add_entry($res['entry']);
+ }
+ }
+ PO::read_line($f, 'clear');
+ if ( false === $res ) {
+ return false;
+ }
+ if ( ! $this->headers && ! $this->entries ) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @param resource $f
+ * @param int $lineno
+ * @return null|false|array
+ */
+ function read_entry($f, $lineno = 0) {
+ $entry = new Translation_Entry();
+ // where were we in the last step
+ // can be: comment, msgctxt, msgid, msgid_plural, msgstr, msgstr_plural
+ $context = '';
+ $msgstr_index = 0;
+ $is_final = create_function('$context', 'return $context == "msgstr" || $context == "msgstr_plural";');
+ while (true) {
+ $lineno++;
+ $line = PO::read_line($f);
+ if (!$line) {
+ if (feof($f)) {
+ if ($is_final($context))
+ break;
+ elseif (!$context) // we haven't read a line and eof came
+ return null;
+ else
+ return false;
+ } else {
+ return false;
+ }
+ }
+ if ($line == "\n") continue;
+ $line = trim($line);
+ if (preg_match('/^#/', $line, $m)) {
+ // the comment is the start of a new entry
+ if ($is_final($context)) {
+ PO::read_line($f, 'put-back');
+ $lineno--;
+ break;
+ }
+ // comments have to be at the beginning
+ if ($context && $context != 'comment') {
+ return false;
+ }
+ // add comment
+ $this->add_comment_to_entry($entry, $line);
+ } elseif (preg_match('/^msgctxt\s+(".*")/', $line, $m)) {
+ if ($is_final($context)) {
+ PO::read_line($f, 'put-back');
+ $lineno--;
+ break;
+ }
+ if ($context && $context != 'comment') {
+ return false;
+ }
+ $context = 'msgctxt';
+ $entry->context .= PO::unpoify($m[1]);
+ } elseif (preg_match('/^msgid\s+(".*")/', $line, $m)) {
+ if ($is_final($context)) {
+ PO::read_line($f, 'put-back');
+ $lineno--;
+ break;
+ }
+ if ($context && $context != 'msgctxt' && $context != 'comment') {
+ return false;
+ }
+ $context = 'msgid';
+ $entry->singular .= PO::unpoify($m[1]);
+ } elseif (preg_match('/^msgid_plural\s+(".*")/', $line, $m)) {
+ if ($context != 'msgid') {
+ return false;
+ }
+ $context = 'msgid_plural';
+ $entry->is_plural = true;
+ $entry->plural .= PO::unpoify($m[1]);
+ } elseif (preg_match('/^msgstr\s+(".*")/', $line, $m)) {
+ if ($context != 'msgid') {
+ return false;
+ }
+ $context = 'msgstr';
+ $entry->translations = array(PO::unpoify($m[1]));
+ } elseif (preg_match('/^msgstr\[(\d+)\]\s+(".*")/', $line, $m)) {
+ if ($context != 'msgid_plural' && $context != 'msgstr_plural') {
+ return false;
+ }
+ $context = 'msgstr_plural';
+ $msgstr_index = $m[1];
+ $entry->translations[$m[1]] = PO::unpoify($m[2]);
+ } elseif (preg_match('/^".*"$/', $line)) {
+ $unpoified = PO::unpoify($line);
+ switch ($context) {
+ case 'msgid':
+ $entry->singular .= $unpoified; break;
+ case 'msgctxt':
+ $entry->context .= $unpoified; break;
+ case 'msgid_plural':
+ $entry->plural .= $unpoified; break;
+ case 'msgstr':
+ $entry->translations[0] .= $unpoified; break;
+ case 'msgstr_plural':
+ $entry->translations[$msgstr_index] .= $unpoified; break;
+ default:
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ if (array() == array_filter($entry->translations, create_function('$t', 'return $t || "0" === $t;'))) {
+ $entry->translations = array();
+ }
+ return array('entry' => $entry, 'lineno' => $lineno);
+ }
+
+ /**
+ * @staticvar string $last_line
+ * @staticvar boolean $use_last_line
+ * @param resource $f
+ * @param string $action
+ * @return boolean
+ */
+ function read_line($f, $action = 'read') {
+ static $last_line = '';
+ static $use_last_line = false;
+ if ('clear' == $action) {
+ $last_line = '';
+ return true;
+ }
+ if ('put-back' == $action) {
+ $use_last_line = true;
+ return true;
+ }
+ $line = $use_last_line? $last_line : fgets($f);
+ $line = ( "\r\n" == substr( $line, -2 ) ) ? rtrim( $line, "\r\n" ) . "\n" : $line;
+ $last_line = $line;
+ $use_last_line = false;
+ return $line;
+ }
+
+ /**
+ * @param Translation_Entry $entry
+ * @param string $po_comment_line
+ */
+ function add_comment_to_entry(&$entry, $po_comment_line) {
+ $first_two = substr($po_comment_line, 0, 2);
+ $comment = trim(substr($po_comment_line, 2));
+ if ('#:' == $first_two) {
+ $entry->references = array_merge($entry->references, preg_split('/\s+/', $comment));
+ } elseif ('#.' == $first_two) {
+ $entry->extracted_comments = trim($entry->extracted_comments . "\n" . $comment);
+ } elseif ('#,' == $first_two) {
+ $entry->flags = array_merge($entry->flags, preg_split('/,\s*/', $comment));
+ } else {
+ $entry->translator_comments = trim($entry->translator_comments . "\n" . $comment);
+ }
+ }
+
+ /**
+ * @param string $s
+ * @return sring
+ */
+ function trim_quotes($s) {
+ if ( substr($s, 0, 1) == '"') $s = substr($s, 1);
+ if ( substr($s, -1, 1) == '"') $s = substr($s, 0, -1);
+ return $s;
+ }