|
@@ -0,0 +1,186 @@
|
|
|
+<?php
|
|
|
+ namespace Juju;
|
|
|
+
|
|
|
+ class MsgFmt {
|
|
|
+ public static function from(string $popath){
|
|
|
+ if(!file_exists($popath)){
|
|
|
+ throw new \Exception("PO file {$popath} does not exist.");
|
|
|
+ }
|
|
|
+ $hash = [];
|
|
|
+ $temp = [];
|
|
|
+ $state = null;
|
|
|
+ $fuzzy = false;
|
|
|
+
|
|
|
+ foreach(explode(
|
|
|
+ "\n",
|
|
|
+ str_replace(
|
|
|
+ ["\r\n", "\r"],
|
|
|
+ ["\n", "\n"],
|
|
|
+ file_get_contents($popath)
|
|
|
+ )
|
|
|
+ ) as $line){
|
|
|
+ $line = trim($line);
|
|
|
+ if ($line !== ''){
|
|
|
+ $exp = explode(' ', $line, 2);
|
|
|
+ $key = $exp[0];
|
|
|
+ if(isset($exp[1])){
|
|
|
+ $data = $exp[1];
|
|
|
+ }
|
|
|
+ switch($key){
|
|
|
+ case '#,':
|
|
|
+ $fuzzy = in_array('fuzzy', preg_split('/,\s*/', $data));
|
|
|
+ case '#':
|
|
|
+ case '#.':
|
|
|
+ case '#:':
|
|
|
+ case '#|':
|
|
|
+
|
|
|
+ if(sizeof($temp) && array_key_exists('msgid', $temp) && array_key_exists('msgstr', $temp)){
|
|
|
+ if (!$fuzzy){
|
|
|
+ $hash[] = $temp;
|
|
|
+ }
|
|
|
+ $temp = [];
|
|
|
+ $state = null;
|
|
|
+ $fuzzy = false;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'msgctxt':
|
|
|
+ case 'msgid':
|
|
|
+ case 'msgid_plural':
|
|
|
+ $state = $key;
|
|
|
+ $temp[$state] = $data;
|
|
|
+ break;
|
|
|
+ case 'msgstr':
|
|
|
+ $state= 'msgstr';
|
|
|
+ $temp[$state][] = $data;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ if(strpos($key, 'msgstr[') !== false){
|
|
|
+ $state= 'msgstr';
|
|
|
+ $temp[$state][] = $data;
|
|
|
+ }else{
|
|
|
+ switch($state){
|
|
|
+ case 'msgctxt':
|
|
|
+ case 'msgid':
|
|
|
+ case 'msgid_plural':
|
|
|
+ $temp[$state] .= "\n" . $line;
|
|
|
+ break;
|
|
|
+ case 'msgstr':
|
|
|
+ $temp[$state][sizeof($temp[$state]) - 1] .= "\n" . $line;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($state === 'msgstr'){
|
|
|
+ $hash[] = $temp;
|
|
|
+ }
|
|
|
+
|
|
|
+ $temp= $hash;
|
|
|
+ $hash= [];
|
|
|
+ foreach($temp as $entry){
|
|
|
+ foreach($entry as &$value){
|
|
|
+ $value = self::clean($value);
|
|
|
+ if($value === false){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $hash[$entry['msgid']] = $entry;
|
|
|
+ }
|
|
|
+ return $hash;
|
|
|
+ }
|
|
|
+ public static function to(string $mopath, array $hash){
|
|
|
+
|
|
|
+ ksort($hash, SORT_STRING);
|
|
|
+
|
|
|
+ $mo = '';
|
|
|
+
|
|
|
+ $offsets = [];
|
|
|
+ $ids = '';
|
|
|
+ $strings = '';
|
|
|
+ foreach($hash as $entry){
|
|
|
+ $id = $entry['msgid'];
|
|
|
+ if(isset($entry['msgid_plural'])){
|
|
|
+ $id .= "\x00" . $entry['msgid_plural'];
|
|
|
+ }
|
|
|
+
|
|
|
+ if(array_key_exists('msgctxt', $entry)){
|
|
|
+ $id = $entry['msgctxt'] . "\x04" . $id;
|
|
|
+ }
|
|
|
+
|
|
|
+ $str = implode("\x00", $entry['msgstr']);
|
|
|
+
|
|
|
+ $offsets[]= [
|
|
|
+ strlen($ids),
|
|
|
+ strlen($id),
|
|
|
+ strlen($strings),
|
|
|
+ strlen($str)
|
|
|
+ ];
|
|
|
+
|
|
|
+ $ids .= $id . "\x00";
|
|
|
+ $strings .= $str . "\x00";
|
|
|
+ }
|
|
|
+
|
|
|
+ $key_start = 7 * 4 + sizeof($hash) * 4 * 4;
|
|
|
+
|
|
|
+ $value_start = $key_start + strlen($ids);
|
|
|
+
|
|
|
+ $key_offsets = [];
|
|
|
+ $value_offsets = [];
|
|
|
+
|
|
|
+ foreach($offsets as $value){
|
|
|
+ list($o1, $l1, $o2, $l2) = $value;
|
|
|
+ $key_offsets[] = $l1;
|
|
|
+ $key_offsets[] = $o1 + $key_start;
|
|
|
+ $value_offsets[] = $l2;
|
|
|
+ $value_offsets[] = $o2 + $value_start;
|
|
|
+ }
|
|
|
+ $offsets= array_merge($key_offsets, $value_offsets);
|
|
|
+
|
|
|
+ $mo .= pack('Iiiiiii', 0x950412de,
|
|
|
+ 0,
|
|
|
+ sizeof($hash),
|
|
|
+ 7 * 4,
|
|
|
+ 7 * 4 + sizeof($hash) * 8,
|
|
|
+ 0,
|
|
|
+ $key_start
|
|
|
+ );
|
|
|
+
|
|
|
+ foreach($offsets as $offset){
|
|
|
+ $mo .= pack('i', $offset);
|
|
|
+ }
|
|
|
+
|
|
|
+ $mo .= $ids;
|
|
|
+
|
|
|
+ $mo .= $strings;
|
|
|
+ file_put_contents($mopath, $mo);
|
|
|
+ }
|
|
|
+ public static function convert(string $popath, string $mopath = null){
|
|
|
+ if(is_null($mopath)){
|
|
|
+ $mopath = dirname($popath).'/'.basename($popath, '.po').'.mo';
|
|
|
+ }
|
|
|
+ self::to($mopath, self::from($popath));
|
|
|
+ }
|
|
|
+ private static function clean($value){
|
|
|
+ if(is_array($value)){
|
|
|
+ foreach($value as $k => $v){
|
|
|
+ $value[$k] = self::clean($v);
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if ($value[0] == '"'){
|
|
|
+ $value = substr($value, 1, -1);
|
|
|
+ }
|
|
|
+ $value = (string)str_replace(
|
|
|
+ '$',
|
|
|
+ '\\$',
|
|
|
+ str_replace("\"\n\"", '', $value)
|
|
|
+ );
|
|
|
+ }
|
|
|
+ return $value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+?>
|