/** * Build gettext MO file * @param string $file * @param string */ private function buildMOFile($file, $identifier) { $dictionary = array_filter($this->dictionary, function ($data) use($identifier) { return $data['file'] === $identifier; }); ksort($dictionary); $metadata = implode("\n", $this->generateMetadata($identifier)); $items = count($dictionary) + 1; $ids = Strings::chr(0x0); $strings = $metadata . Strings::chr(0x0); $idsOffsets = array(0, 28 + $items * 16); $stringsOffsets = array(array(0, strlen($metadata))); foreach ($dictionary as $key => $value) { $id = $key; if (is_array($value['original']) && count($value['original']) > 1) { $id .= Strings::chr(0x0) . end($value['original']); } $string = implode(Strings::chr(0x0), $value['translation']); $idsOffsets[] = strlen($id); $idsOffsets[] = strlen($ids) + 28 + $items * 16; $stringsOffsets[] = array(strlen($strings), strlen($string)); $ids .= $id . Strings::chr(0x0); $strings .= $string . Strings::chr(0x0); } $valuesOffsets = array(); foreach ($stringsOffsets as $offset) { list($all, $one) = $offset; $valuesOffsets[] = $one; $valuesOffsets[] = $all + strlen($ids) + 28 + $items * 16; } $offsets = array_merge($idsOffsets, $valuesOffsets); $mo = pack('Iiiiiii', 0x950412de, 0, $items, 28, 28 + $items * 8, 0, 28 + $items * 16); foreach ($offsets as $offset) { $mo .= pack('i', $offset); } file_put_contents($file, $mo . $ids . $strings); }
private function cbString($m) { static $mapping = array('t' => "\t", 'n' => "\n", '"' => '"', '\\' => '\\', '/' => '/', '_' => " "); $sq = $m[0]; if (isset($mapping[$sq[1]])) { return $mapping[$sq[1]]; } elseif ($sq[1] === 'u' && strlen($sq) === 6) { return Strings::chr(hexdec(substr($sq, 2))); } elseif ($sq[1] === 'x' && strlen($sq) === 4) { return chr(hexdec(substr($sq, 2))); } else { $this->error("Invalid escaping sequence {$sq}"); } }
/** * @param string * @return \Nella\Localization\Dictionary * @throws \Nette\InvalidArgumentException */ public function load($lang, Dictionary $dictionary) { $path = str_replace(array('%dir%', '%lang%'), array($dictionary->dir, $lang), $this->fileMask); if (!file_exists($path)) { return; } if (@filesize($path) < 10) { throw new \Nette\InvalidArgumentException("File '$path' is not a gettext file"); } $handle = @fopen($path, "rb"); $endian = FALSE; $read = function($bytes) use ($handle, $endian) { $data = fread($handle, 4 * $bytes); return $endian === FALSE ? unpack('V'.$bytes, $data) : unpack('N'.$bytes, $data); }; $input = $read(1); if (Strings::lower(substr(dechex($input[1]), -8)) == "950412de") { $endian = FALSE; } elseif (Strings::lower(substr(dechex($input[1]), -8)) == "de120495") { $endian = TRUE; } else { throw new \Nette\InvalidArgumentException("File '$path' is not a gettext file"); } $input = $read(1); $input = $read(1); $total = $input[1]; $input = $read(1); $originalOffset = $input[1]; $input = $read(1); $translationOffset = $input[1]; fseek($handle, $originalOffset); $orignalTmp = $read(2 * $total); fseek($handle, $translationOffset); $translationTmp = $read(2 * $total); $metadata = array(); for ($i = 0; $i < $total; ++$i) { if ($orignalTmp[$i * 2 + 1] != 0) { fseek($handle, $orignalTmp[$i * 2 + 2]); $original = @fread($handle, $orignalTmp[$i * 2 + 1]); } else { $original = ""; } if ($translationTmp[$i * 2 + 1] != 0) { fseek($handle, $translationTmp[$i * 2 + 2]); $translation = fread($handle, $translationTmp[$i * 2 + 1]); if ($original === "") { $metadata += $this->decodeMetadata($translation); continue; } $original = explode(Strings::chr(0x00), $original); $translation = explode(Strings::chr(0x00), $translation); // needed $original data (if array) ? $dictionary->addTranslation(is_array($original) ? $original[0] : $original, $translation); } } $dictionary->metadata = $metadata; if (isset($metadata['Plural-Forms'])) { $dictionary->pluralForm = $metadata['Plural-Forms']; } }