forked from GithubBackups/tinyib
152 lines
4.9 KiB
PHP
152 lines
4.9 KiB
PHP
<?php
|
|
declare(strict_types = 1);
|
|
|
|
namespace Gettext\Generator;
|
|
|
|
use Gettext\Translation;
|
|
use Gettext\Translations;
|
|
|
|
final class MoGenerator extends Generator
|
|
{
|
|
private $includeHeaders = false;
|
|
|
|
public function includeHeaders(bool $includeHeaders = true): self
|
|
{
|
|
$this->includeHeaders = $includeHeaders;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function generateString(Translations $translations): string
|
|
{
|
|
$messages = [];
|
|
|
|
if ($this->includeHeaders) {
|
|
$lines = [];
|
|
|
|
foreach ($translations->getHeaders() as $name => $value) {
|
|
$lines[] = sprintf('%s: %s', $name, $value);
|
|
}
|
|
|
|
$messages[''] = implode("\n", $lines);
|
|
}
|
|
|
|
foreach ($translations as $translation) {
|
|
if (!$translation->getTranslation() || $translation->isDisabled()) {
|
|
continue;
|
|
}
|
|
|
|
if ($context = $translation->getContext()) {
|
|
$originalString = "{$context}\x04{$translation->getOriginal()}";
|
|
} else {
|
|
$originalString = $translation->getOriginal();
|
|
}
|
|
|
|
$messages[$originalString] = $translation;
|
|
}
|
|
|
|
ksort($messages);
|
|
$numEntries = count($messages);
|
|
$originalsTable = '';
|
|
$translationsTable = '';
|
|
$originalsIndex = [];
|
|
$translationsIndex = [];
|
|
$pluralForm = $translations->getHeaders()->getPluralForm();
|
|
$pluralSize = is_array($pluralForm) ? ($pluralForm[0] - 1) : null;
|
|
|
|
foreach ($messages as $originalString => $translation) {
|
|
if (is_string($translation)) {
|
|
$translationString = $translation;
|
|
} elseif (self::hasPluralTranslations($translation)) {
|
|
$originalString .= "\x00{$translation->getPlural()}";
|
|
$translationString = "{$translation->getTranslation()}\x00"
|
|
.implode("\x00", $translation->getPluralTranslations($pluralSize));
|
|
} else {
|
|
$translationString = $translation->getTranslation();
|
|
}
|
|
|
|
$originalsIndex[] = [
|
|
'relativeOffset' => strlen($originalsTable),
|
|
'length' => strlen((string) $originalString),
|
|
];
|
|
$originalsTable .= $originalString."\x00";
|
|
$translationsIndex[] = [
|
|
'relativeOffset' => strlen($translationsTable),
|
|
'length' => strlen($translationString),
|
|
];
|
|
$translationsTable .= $translationString."\x00";
|
|
}
|
|
|
|
// Offset of table with the original strings index: right after the header (which is 7 words)
|
|
$originalsIndexOffset = 7 * 4;
|
|
|
|
// Size of table with the original strings index
|
|
$originalsIndexSize = $numEntries * (4 + 4);
|
|
|
|
// Offset of table with the translation strings index: right after the original strings index table
|
|
$translationsIndexOffset = $originalsIndexOffset + $originalsIndexSize;
|
|
|
|
// Size of table with the translation strings index
|
|
$translationsIndexSize = $numEntries * (4 + 4);
|
|
|
|
// Hashing table starts after the header and after the index table
|
|
$originalsStringsOffset = $translationsIndexOffset + $translationsIndexSize;
|
|
|
|
// Translations start after the keys
|
|
$translationsStringsOffset = $originalsStringsOffset + strlen($originalsTable);
|
|
|
|
// Let's generate the .mo file binary data
|
|
$mo = '';
|
|
|
|
// Magic number
|
|
$mo .= pack('L', 0x950412de);
|
|
|
|
// File format revision
|
|
$mo .= pack('L', 0);
|
|
|
|
// Number of strings
|
|
$mo .= pack('L', $numEntries);
|
|
|
|
// Offset of table with original strings
|
|
$mo .= pack('L', $originalsIndexOffset);
|
|
|
|
// Offset of table with translation strings
|
|
$mo .= pack('L', $translationsIndexOffset);
|
|
|
|
// Size of hashing table: we don't use it.
|
|
$mo .= pack('L', 0);
|
|
|
|
// Offset of hashing table: it would start right after the translations index table
|
|
$mo .= pack('L', $translationsIndexOffset + $translationsIndexSize);
|
|
|
|
// Write the lengths & offsets of the original strings
|
|
foreach ($originalsIndex as $info) {
|
|
$mo .= pack('L', $info['length']);
|
|
$mo .= pack('L', $originalsStringsOffset + $info['relativeOffset']);
|
|
}
|
|
|
|
// Write the lengths & offsets of the translated strings
|
|
foreach ($translationsIndex as $info) {
|
|
$mo .= pack('L', $info['length']);
|
|
$mo .= pack('L', $translationsStringsOffset + $info['relativeOffset']);
|
|
}
|
|
|
|
// Write original strings
|
|
$mo .= $originalsTable;
|
|
|
|
// Write translation strings
|
|
$mo .= $translationsTable;
|
|
|
|
return $mo;
|
|
}
|
|
|
|
private static function hasPluralTranslations(Translation $translation): bool
|
|
{
|
|
if (!$translation->getPlural()) {
|
|
return false;
|
|
}
|
|
|
|
return implode('', $translation->getPluralTranslations()) !== '';
|
|
}
|
|
}
|