/**
* Class for working with PO files
*
- * @version $Id: po.php 123 2009-05-13 19:35:43Z nbachiyski $
+ * @version $Id: po.php 1158 2015-11-20 04:31:23Z dd32 $
* @package pomo
* @subpackage po
*/
require_once dirname(__FILE__) . '/translations.php';
-define('PO_MAX_LINE_LEN', 79);
+if ( ! defined( 'PO_MAX_LINE_LEN' ) ) {
+ define('PO_MAX_LINE_LEN', 79);
+}
ini_set('auto_detect_line_endings', 1);
/**
* Routines for working with PO files
*/
+if ( ! class_exists( 'PO', false ) ):
class PO extends Gettext_Translations {
-
+
+ var $comments_before_headers = '';
/**
* Exports headers to a PO entry
$header_string.= "$header: $value\n";
}
$poified = PO::poify($header_string);
- return rtrim("msgid \"\"\nmsgstr $poified");
+ if ($this->comments_before_headers)
+ $before_headers = $this->prepend_each_line(rtrim($this->comments_before_headers)."\n", '# ');
+ else
+ $before_headers = '';
+ return rtrim("{$before_headers}msgid \"\"\nmsgstr $poified");
}
/**
return fclose($fh);
}
+ /**
+ * Text to include as a comment before the start of the PO contents
+ *
+ * Doesn't need to include # in the beginning of lines, these are added automatically
+ */
+ function set_comment_before_headers( $text ) {
+ $this->comments_before_headers = $text;
+ }
+
/**
* Formats a string in PO-style
*
* @param string $string the string to format
* @return string the poified string
*/
- function poify($string) {
+ public static function poify($string) {
$quote = '"';
$slash = '\\';
$newline = "\n";
$po = str_replace("$newline$quote$quote", '', $po);
return $po;
}
-
+
/**
* Gives back the original string from a PO-formatted string
- *
+ *
* @static
* @param string $string PO-formatted string
* @return string enascaped string
*/
- function unpoify($string) {
- $escapes = array('t' => "\t", 'n' => "\n", '\\' => '\\');
+ public static function unpoify($string) {
+ $escapes = array('t' => "\t", 'n' => "\n", 'r' => "\r", '\\' => '\\');
$lines = array_map('trim', explode("\n", $string));
$lines = array_map(array('PO', 'trim_quotes'), $lines);
$unpoified = '';
}
}
}
+
+ // Standardise the line endings on imported content, technically PO files shouldn't contain \r
+ $unpoified = str_replace( array( "\r\n", "\r" ), "\n", $unpoified );
+
return $unpoified;
}
/**
- * Inserts $with in the beginning of every new line of $string and
+ * Inserts $with in the beginning of every new line of $string and
* returns the modified string
*
* @static
* @param string $string prepend lines in this string
* @param string $with prepend lines with this string
*/
- function prepend_each_line($string, $with) {
+ public static function prepend_each_line($string, $with) {
$php_with = var_export($with, true);
$lines = explode("\n", $string);
// do not prepend the string on the last empty line, artefact by explode
* @param string $char character to denote a special PO comment,
* like :, default is a space
*/
- function comment_block($text, $char=' ') {
+ public static function comment_block($text, $char=' ') {
$text = wordwrap($text, PO_MAX_LINE_LEN - 3);
return PO::prepend_each_line($text, "#$char ");
}
* Builds a string from the entry for inclusion in PO file
*
* @static
- * @param object &$entry the entry to convert to po string
- * @return string|bool PO-style formatted string for the entry or
+ * @param Translation_Entry &$entry the entry to convert to po string
+ * @return false|string PO-style formatted string for the entry or
* false if the entry is empty
*/
- function export_entry(&$entry) {
- if (is_null($entry->singular)) return false;
+ public static function export_entry(&$entry) {
+ if ( null === $entry->singular || '' === $entry->singular ) return false;
$po = array();
if (!empty($entry->translator_comments)) $po[] = PO::comment_block($entry->translator_comments);
if (!empty($entry->extracted_comments)) $po[] = PO::comment_block($entry->extracted_comments, '.');
if (!empty($entry->references)) $po[] = PO::comment_block(implode(' ', $entry->references), ':');
if (!empty($entry->flags)) $po[] = PO::comment_block(implode(", ", $entry->flags), ',');
- if (!is_null($entry->context)) $po[] = 'msgctxt '.PO::poify($entry->context);
+ if ($entry->context) $po[] = 'msgctxt '.PO::poify($entry->context);
$po[] = 'msgid '.PO::poify($entry->singular);
if (!$entry->is_plural) {
$translation = empty($entry->translations)? '' : $entry->translations[0];
+ $translation = PO::match_begin_and_end_newlines( $translation, $entry->singular );
$po[] = 'msgstr '.PO::poify($translation);
} else {
$po[] = 'msgid_plural '.PO::poify($entry->plural);
$translations = empty($entry->translations)? array('', '') : $entry->translations;
foreach($translations as $i => $translation) {
+ $translation = PO::match_begin_and_end_newlines( $translation, $entry->plural );
$po[] = "msgstr[$i] ".PO::poify($translation);
}
}
return implode("\n", $po);
}
+ public static function match_begin_and_end_newlines( $translation, $original ) {
+ if ( '' === $translation ) {
+ return $translation;
+ }
+
+ $original_begin = "\n" === substr( $original, 0, 1 );
+ $original_end = "\n" === substr( $original, -1 );
+ $translation_begin = "\n" === substr( $translation, 0, 1 );
+ $translation_end = "\n" === substr( $translation, -1 );
+
+ if ( $original_begin ) {
+ if ( ! $translation_begin ) {
+ $translation = "\n" . $translation;
+ }
+ } elseif ( $translation_begin ) {
+ $translation = ltrim( $translation, "\n" );
+ }
+
+ if ( $original_end ) {
+ if ( ! $translation_end ) {
+ $translation .= "\n";
+ }
+ } elseif ( $translation_end ) {
+ $translation = rtrim( $translation, "\n" );
+ }
+
+ return $translation;
+ }
+
+ /**
+ * @param string $filename
+ * @return boolean
+ */
function import_from_file($filename) {
$f = fopen($filename, 'r');
if (!$f) return false;
}
}
PO::read_line($f, 'clear');
- return $res !== false;
+ 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
return false;
}
// add comment
- $this->add_comment_to_entry($entry, $line);;
+ $this->add_comment_to_entry($entry, $line);
} elseif (preg_match('/^msgctxt\s+(".*")/', $line, $m)) {
if ($is_final($context)) {
PO::read_line($f, 'put-back');
return false;
}
}
- if (array() == array_filter($entry->translations)) $entry->translations = array();
+ 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;
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));
$entry->translator_comments = trim($entry->translator_comments . "\n" . $comment);
}
}
-
- function trim_quotes($s) {
+
+ /**
+ * @param string $s
+ * @return sring
+ */
+ public static 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;
}
}
-?>
+endif;