51 } |
51 } |
52 |
52 |
53 /** |
53 /** |
54 * Exports all entries to PO format |
54 * Exports all entries to PO format |
55 * |
55 * |
56 * @return string sequence of mgsgid/msgstr PO strings, doesn't containt newline at the end |
56 * @return string sequence of msgid/msgstr PO strings, doesn't contain a newline at the end |
57 */ |
57 */ |
58 public function export_entries() { |
58 public function export_entries() { |
59 // TODO: Sorting. |
59 // TODO: Sorting. |
60 return implode( "\n\n", array_map( array( 'PO', 'export_entry' ), $this->entries ) ); |
60 return implode( "\n\n", array_map( array( 'PO', 'export_entry' ), $this->entries ) ); |
61 } |
61 } |
62 |
62 |
63 /** |
63 /** |
64 * Exports the whole PO file as a string |
64 * Exports the whole PO file as a string |
65 * |
65 * |
66 * @param bool $include_headers whether to include the headers in the export |
66 * @param bool $include_headers whether to include the headers in the export |
67 * @return string ready for inclusion in PO file string for headers and all the enrtries |
67 * @return string ready for inclusion in PO file string for headers and all the entries |
68 */ |
68 */ |
69 public function export( $include_headers = true ) { |
69 public function export( $include_headers = true ) { |
70 $res = ''; |
70 $res = ''; |
71 if ( $include_headers ) { |
71 if ( $include_headers ) { |
72 $res .= $this->export_headers(); |
72 $res .= $this->export_headers(); |
108 } |
108 } |
109 |
109 |
110 /** |
110 /** |
111 * Formats a string in PO-style |
111 * Formats a string in PO-style |
112 * |
112 * |
113 * @param string $string the string to format |
113 * @param string $input_string the string to format |
114 * @return string the poified string |
114 * @return string the poified string |
115 */ |
115 */ |
116 public static function poify( $string ) { |
116 public static function poify( $input_string ) { |
117 $quote = '"'; |
117 $quote = '"'; |
118 $slash = '\\'; |
118 $slash = '\\'; |
119 $newline = "\n"; |
119 $newline = "\n"; |
120 |
120 |
121 $replaces = array( |
121 $replaces = array( |
122 "$slash" => "$slash$slash", |
122 "$slash" => "$slash$slash", |
123 "$quote" => "$slash$quote", |
123 "$quote" => "$slash$quote", |
124 "\t" => '\t', |
124 "\t" => '\t', |
125 ); |
125 ); |
126 |
126 |
127 $string = str_replace( array_keys( $replaces ), array_values( $replaces ), $string ); |
127 $input_string = str_replace( array_keys( $replaces ), array_values( $replaces ), $input_string ); |
128 |
128 |
129 $po = $quote . implode( "${slash}n$quote$newline$quote", explode( $newline, $string ) ) . $quote; |
129 $po = $quote . implode( "{$slash}n{$quote}{$newline}{$quote}", explode( $newline, $input_string ) ) . $quote; |
130 // Add empty string on first line for readbility. |
130 // Add empty string on first line for readability. |
131 if ( false !== strpos( $string, $newline ) && |
131 if ( str_contains( $input_string, $newline ) && |
132 ( substr_count( $string, $newline ) > 1 || substr( $string, -strlen( $newline ) ) !== $newline ) ) { |
132 ( substr_count( $input_string, $newline ) > 1 || substr( $input_string, -strlen( $newline ) ) !== $newline ) ) { |
133 $po = "$quote$quote$newline$po"; |
133 $po = "$quote$quote$newline$po"; |
134 } |
134 } |
135 // Remove empty strings. |
135 // Remove empty strings. |
136 $po = str_replace( "$newline$quote$quote", '', $po ); |
136 $po = str_replace( "$newline$quote$quote", '', $po ); |
137 return $po; |
137 return $po; |
138 } |
138 } |
139 |
139 |
140 /** |
140 /** |
141 * Gives back the original string from a PO-formatted string |
141 * Gives back the original string from a PO-formatted string |
142 * |
142 * |
143 * @param string $string PO-formatted string |
143 * @param string $input_string PO-formatted string |
144 * @return string enascaped string |
144 * @return string unescaped string |
145 */ |
145 */ |
146 public static function unpoify( $string ) { |
146 public static function unpoify( $input_string ) { |
147 $escapes = array( |
147 $escapes = array( |
148 't' => "\t", |
148 't' => "\t", |
149 'n' => "\n", |
149 'n' => "\n", |
150 'r' => "\r", |
150 'r' => "\r", |
151 '\\' => '\\', |
151 '\\' => '\\', |
152 ); |
152 ); |
153 $lines = array_map( 'trim', explode( "\n", $string ) ); |
153 $lines = array_map( 'trim', explode( "\n", $input_string ) ); |
154 $lines = array_map( array( 'PO', 'trim_quotes' ), $lines ); |
154 $lines = array_map( array( 'PO', 'trim_quotes' ), $lines ); |
155 $unpoified = ''; |
155 $unpoified = ''; |
156 $previous_is_backslash = false; |
156 $previous_is_backslash = false; |
157 foreach ( $lines as $line ) { |
157 foreach ( $lines as $line ) { |
158 preg_match_all( '/./u', $line, $chars ); |
158 preg_match_all( '/./u', $line, $chars ); |
176 |
176 |
177 return $unpoified; |
177 return $unpoified; |
178 } |
178 } |
179 |
179 |
180 /** |
180 /** |
181 * Inserts $with in the beginning of every new line of $string and |
181 * Inserts $with in the beginning of every new line of $input_string and |
182 * returns the modified string |
182 * returns the modified string |
183 * |
183 * |
184 * @param string $string prepend lines in this string |
184 * @param string $input_string prepend lines in this string |
185 * @param string $with prepend lines with this string |
185 * @param string $with prepend lines with this string |
186 */ |
186 */ |
187 public static function prepend_each_line( $string, $with ) { |
187 public static function prepend_each_line( $input_string, $with ) { |
188 $lines = explode( "\n", $string ); |
188 $lines = explode( "\n", $input_string ); |
189 $append = ''; |
189 $append = ''; |
190 if ( "\n" === substr( $string, -1 ) && '' === end( $lines ) ) { |
190 if ( "\n" === substr( $input_string, -1 ) && '' === end( $lines ) ) { |
191 /* |
191 /* |
192 * Last line might be empty because $string was terminated |
192 * Last line might be empty because $input_string was terminated |
193 * with a newline, remove it from the $lines array, |
193 * with a newline, remove it from the $lines array, |
194 * we'll restore state by re-terminating the string at the end. |
194 * we'll restore state by re-terminating the string at the end. |
195 */ |
195 */ |
196 array_pop( $lines ); |
196 array_pop( $lines ); |
197 $append = "\n"; |
197 $append = "\n"; |
363 $line = trim( $line ); |
363 $line = trim( $line ); |
364 if ( preg_match( '/^#/', $line, $m ) ) { |
364 if ( preg_match( '/^#/', $line, $m ) ) { |
365 // The comment is the start of a new entry. |
365 // The comment is the start of a new entry. |
366 if ( self::is_final( $context ) ) { |
366 if ( self::is_final( $context ) ) { |
367 PO::read_line( $f, 'put-back' ); |
367 PO::read_line( $f, 'put-back' ); |
368 $lineno--; |
368 --$lineno; |
369 break; |
369 break; |
370 } |
370 } |
371 // Comments have to be at the beginning. |
371 // Comments have to be at the beginning. |
372 if ( $context && 'comment' !== $context ) { |
372 if ( $context && 'comment' !== $context ) { |
373 return false; |
373 return false; |
375 // Add comment. |
375 // Add comment. |
376 $this->add_comment_to_entry( $entry, $line ); |
376 $this->add_comment_to_entry( $entry, $line ); |
377 } elseif ( preg_match( '/^msgctxt\s+(".*")/', $line, $m ) ) { |
377 } elseif ( preg_match( '/^msgctxt\s+(".*")/', $line, $m ) ) { |
378 if ( self::is_final( $context ) ) { |
378 if ( self::is_final( $context ) ) { |
379 PO::read_line( $f, 'put-back' ); |
379 PO::read_line( $f, 'put-back' ); |
380 $lineno--; |
380 --$lineno; |
381 break; |
381 break; |
382 } |
382 } |
383 if ( $context && 'comment' !== $context ) { |
383 if ( $context && 'comment' !== $context ) { |
384 return false; |
384 return false; |
385 } |
385 } |
386 $context = 'msgctxt'; |
386 $context = 'msgctxt'; |
387 $entry->context .= PO::unpoify( $m[1] ); |
387 $entry->context .= PO::unpoify( $m[1] ); |
388 } elseif ( preg_match( '/^msgid\s+(".*")/', $line, $m ) ) { |
388 } elseif ( preg_match( '/^msgid\s+(".*")/', $line, $m ) ) { |
389 if ( self::is_final( $context ) ) { |
389 if ( self::is_final( $context ) ) { |
390 PO::read_line( $f, 'put-back' ); |
390 PO::read_line( $f, 'put-back' ); |
391 $lineno--; |
391 --$lineno; |
392 break; |
392 break; |
393 } |
393 } |
394 if ( $context && 'msgctxt' !== $context && 'comment' !== $context ) { |
394 if ( $context && 'msgctxt' !== $context && 'comment' !== $context ) { |
395 return false; |
395 return false; |
396 } |
396 } |
503 /** |
503 /** |
504 * @param string $s |
504 * @param string $s |
505 * @return string |
505 * @return string |
506 */ |
506 */ |
507 public static function trim_quotes( $s ) { |
507 public static function trim_quotes( $s ) { |
508 if ( '"' === substr( $s, 0, 1 ) ) { |
508 if ( str_starts_with( $s, '"' ) ) { |
509 $s = substr( $s, 1 ); |
509 $s = substr( $s, 1 ); |
510 } |
510 } |
511 if ( '"' === substr( $s, -1, 1 ) ) { |
511 if ( str_ends_with( $s, '"' ) ) { |
512 $s = substr( $s, 0, -1 ); |
512 $s = substr( $s, 0, -1 ); |
513 } |
513 } |
514 return $s; |
514 return $s; |
515 } |
515 } |
516 } |
516 } |