tinyib/inc/gettext/src/Generator/MoGenerator.php
Trevor Slocum 0b02c3fdb5 Update Gettext library
Relates to #254.
2022-03-10 20:36:18 -08:00

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()) !== '';
}
}