/** * Add the headers found to the translations instance. * * @param string $headers * @param Translations $translations * * @return array */ private static function extractHeaders($headers, Translations $translations) { $headers = explode("\n", $headers); $currentHeader = null; foreach ($headers as $line) { $line = self::convertString($line); if ($line === '') { continue; } if (self::isHeaderDefinition($line)) { $header = array_map('trim', explode(':', $line, 2)); $currentHeader = $header[0]; $translations->setHeader($currentHeader, $header[1]); } else { $entry = $translations->getHeader($currentHeader); $translations->setHeader($currentHeader, $entry . $line); } } }
/** * {@inheritdoc} */ public static function fromString($string, Translations $translations, array $options = []) { $xml = new SimpleXMLElement($string, null, false); foreach ($xml->file as $file) { if (isset($file->notes)) { foreach ($file->notes->note as $note) { $translations->setHeader($note['id'], (string) $note); } } foreach ($file->unit as $unit) { foreach ($unit->segment as $segment) { $targets = []; foreach ($segment->target as $target) { $targets[] = (string) $target; } $translation = new Translation(null, (string) $segment->source); $translation->setTranslation(array_shift($targets)); $translation->setPluralTranslations($targets); if (isset($unit->notes)) { foreach ($unit->notes->note as $note) { switch ($note['category']) { case 'context': $translation = $translation->getClone((string) $note); break; case 'extracted-comment': $translation->addExtractedComment((string) $note); break; case 'flag': $translation->addFlag((string) $note); break; case 'reference': $ref = explode(':', (string) $note, 2); $translation->addReference($ref[0], isset($ref[1]) ? $ref[1] : null); break; default: $translation->addComment((string) $note); break; } } } $translations[] = $translation; } } } }
/** * Handle an array of translations and append to the Translations instance. * * @param array $content * @param Translations $translations */ public static function extract(array $content, Translations $translations) { $messages = current($content); $headers = isset($messages['']) ? $messages[''] : null; unset($messages['']); if (!empty($headers['domain'])) { $translations->setDomain($headers['domain']); } if (!empty($headers['lang'])) { $translations->setLanguage($headers['lang']); } if (!empty($headers['plural-forms'])) { $translations->setHeader(Translations::HEADER_PLURAL, $headers['plural-forms']); } $context_glue = '\\u0004'; foreach ($messages as $key => $translation) { $key = explode($context_glue, $key); $context = isset($key[1]) ? array_shift($key) : ''; $translations->insert($context, array_shift($key))->setTranslation(array_shift($translation))->setPluralTranslations($translation); } }
/** * Extract the entries from a multidimensional array. * * @param array $messages * @param Translations $translations */ private static function fromArray(array $messages, Translations $translations) { if (!empty($messages['domain'])) { $translations->setDomain($messages['domain']); } if (!empty($messages['plural-forms'])) { $translations->setHeader(Translations::HEADER_PLURAL, $messages['plural-forms']); } foreach ($messages['messages'] as $context => $contextTranslations) { foreach ($contextTranslations as $original => $value) { if ($context === '' && $original === '') { self::extractHeaders(is_array($value) ? array_shift($value) : $value, $translations); continue; } $translation = $translations->insert($context, $original); if (is_array($value)) { $translation->setTranslation(array_shift($value)); $translation->setPluralTranslations($value); } else { $translation->setTranslation($value); } } } }
protected function execute(InputInterface $input, OutputInterface $output) { $container = $this->getContainer(); $filesystem = new Filesystem(); $locator = $container->get("agit.common.filecollector"); $bundles = $container->getParameter("kernel.bundles"); $catalogPath = $container->getParameter("kernel.root_dir") . "/{$this->catalogSubdir}"; $this->getContainer()->get("event_dispatcher")->dispatch("agit.intl.global.translations", new TranslationsEvent($this)); foreach ($container->getParameter("agit.intl.locales") as $locale) { $catalog = new Translations(); $messagesPath = "{$catalogPath}/{$locale}/LC_MESSAGES"; $catalogFile = "{$messagesPath}/agit.po"; $oldCatalog = $filesystem->exists($catalogFile) ? Translations::fromPoFile($catalogFile) : new Translations(); foreach ($oldCatalog as $translation) { $translation->deleteReferences(); } $catalog->mergeWith($oldCatalog, 0); foreach ($bundles as $alias => $namespace) { $bundlePath = $locator->resolve($alias); $bundleCatalogFile = "{$bundlePath}/{$this->catalogSubdir}/bundle.{$locale}.po"; $bundleCatalog = $filesystem->exists($bundleCatalogFile) ? Translations::fromPoFile($bundleCatalogFile) : new Translations(); $catalog->mergeWith($bundleCatalog, Merge::ADD); } if (isset($this->extraTranslations[$locale])) { foreach ($this->extraTranslations[$locale] as $translation) { $catalog[] = $translation; } } // NOTE: we delete all headers and only set language in order to avoid garbage commits $catalog->deleteHeaders(); $catalog->setLanguage($locale); $catalog->setHeader("Content-Type", "text/plain; charset=UTF-8"); $filesystem->dumpFile($catalogFile, $catalog->toPoString()); $filesystem->dumpFile("{$messagesPath}/agit.mo", $catalog->toMoString()); } }
public static function load() { $locale = self::$locale; # IMPORTANT: locale must be installed in server! # sudo locale-gen es_ES.UTF-8 # sudo update-locale // $_ENV["LANG"] = $locale; // $_ENV["LANGUAGE"] = $locale; // $_ENV["LC_MESSAGES"] = $locale; // $_ENV["LC_PAPER"] = $locale; // $_ENV["LC_TIME"] = $locale; // $_ENV["LC_MONETARY"] = $locale; // setlocale(LC_MESSAGES, $locale); // setlocale(LC_COLLATE, $locale); // setlocale(LC_TIME, $locale); // setlocale(LC_MONETARY, $locale); // bindtextdomain(self::$config['domain'], self::$config['storage']); // bind_textdomain_codeset(self::$config['domain'], 'UTF-8'); // textdomain(self::$config['domain']); # Also, we will work with gettext/gettext library # because PHP gones crazy when mo files are updated $path = base_path() . "/" . dirname(self::getFile(self::$locale)); $file = $path . '/' . self::$config['domain']; if (is_file($file . '.mo')) { $translations = Translations::fromMoFile($file . '.mo'); } if (is_file($file . '.po')) { $translationsPo = Translations::fromPoFile($file . '.po'); } if ($translations) { $translations->mergeWith($translationsPo); } else { $translations = $translationsPo; } if (!$translations) { $translations = new Translations(); } $translations->setLanguage($locale); $translations->setHeader('LANGUAGE', $locale); self::$currentTranslation = $translations; // $trans = new Translator(); // $trans->loadTranslations($translations); // Translator::initGettextFunctions($trans); }
/** * {@inheritDoc} */ public static function fromString($string, Translations $translations = null, $file = '') { if ($translations === null) { $translations = new Translations(); } $stream = new StringReader($string); $magic = self::readInt($stream, 'V'); if ($magic === self::MAGIC1 || $magic === self::MAGIC3) { //to make sure it works for 64-bit platforms $byteOrder = 'V'; //low endian } elseif ($magic === (self::MAGIC2 & 0xffffffff)) { $byteOrder = 'N'; //big endian } else { throw new \Exception('Not MO file'); } self::readInt($stream, $byteOrder); $total = self::readInt($stream, $byteOrder); //total string count $originals = self::readInt($stream, $byteOrder); //offset of original table $tran = self::readInt($stream, $byteOrder); //offset of translation table $stream->seekto($originals); $table_originals = self::readIntArray($stream, $byteOrder, $total * 2); $stream->seekto($tran); $table_translations = self::readIntArray($stream, $byteOrder, $total * 2); for ($i = 0; $i < $total; $i++) { $stream->seekto($table_originals[$i * 2 + 2]); $original = $stream->read($table_originals[$i * 2 + 1]); $stream->seekto($table_translations[$i * 2 + 2]); $translated = $stream->read($table_translations[$i * 2 + 1]); if ($original === '') { // Headers foreach (explode("\n", $translated) as $headerLine) { if ($headerLine !== '') { $headerChunks = preg_split('/:\\s*/', $headerLine, 2); $translations->setHeader($headerChunks[0], isset($headerChunks[1]) ? $headerChunks[1] : ''); } } } else { $chunks = explode("", $original, 2); if (isset($chunks[1])) { $context = $chunks[0]; $original = $chunks[1]; } else { $context = ''; } $chunks = explode("", $original, 2); if (isset($chunks[1])) { $original = $chunks[0]; $plural = $chunks[1]; } else { $plural = ''; } $translation = $translations->insert($context, $original, $plural); if ($translated !== '') { if ($plural === '') { $translation->setTranslation($translated); } else { foreach (explode("", $translated) as $pluralIndex => $pluralValue) { if ($pluralIndex === 0) { $translation->setTranslation($pluralValue); } else { $translation->setPluralTranslation($pluralValue, $pluralIndex - 1); } } } } } } return $translations; }
/** * {@inheritdoc} */ public static function fromString($string, Translations $translations, array $options = []) { $stream = new StringReader($string); $magic = self::readInt($stream, 'V'); if ($magic === self::MAGIC1 || $magic === self::MAGIC3) { //to make sure it works for 64-bit platforms $byteOrder = 'V'; //low endian } elseif ($magic === (self::MAGIC2 & 0xffffffff)) { $byteOrder = 'N'; //big endian } else { throw new Exception('Not MO file'); } self::readInt($stream, $byteOrder); $total = self::readInt($stream, $byteOrder); //total string count $originals = self::readInt($stream, $byteOrder); //offset of original table $tran = self::readInt($stream, $byteOrder); //offset of translation table $stream->seekto($originals); $table_originals = self::readIntArray($stream, $byteOrder, $total * 2); $stream->seekto($tran); $table_translations = self::readIntArray($stream, $byteOrder, $total * 2); for ($i = 0; $i < $total; ++$i) { $next = $i * 2; $stream->seekto($table_originals[$next + 2]); $original = $stream->read($table_originals[$next + 1]); $stream->seekto($table_translations[$next + 2]); $translated = $stream->read($table_translations[$next + 1]); if ($original === '') { // Headers foreach (explode("\n", $translated) as $headerLine) { if ($headerLine === '') { continue; } $headerChunks = preg_split('/:\\s*/', $headerLine, 2); $translations->setHeader($headerChunks[0], isset($headerChunks[1]) ? $headerChunks[1] : ''); } continue; } $chunks = explode("", $original, 2); if (isset($chunks[1])) { $context = $chunks[0]; $original = $chunks[1]; } else { $context = ''; } $chunks = explode("", $original, 2); if (isset($chunks[1])) { $original = $chunks[0]; $plural = $chunks[1]; } else { $plural = ''; } $translation = $translations->insert($context, $original, $plural); if ($translated === '') { continue; } if ($plural === '') { $translation->setTranslation($translated); continue; } $v = explode("", $translated); $translation->setTranslation(array_shift($v)); $translation->setPluralTranslations($v); } }
protected function execute(InputInterface $input, OutputInterface $output) { try { $vsh = Core::make('helper/validation/strings'); /* @var \Concrete\Core\Utility\Service\Validation\Strings $vsh */ $fh = Core::make('helper/file'); /* @var \Concrete\Core\File\Service\File $fh */ // Let's determine the package handle, directory and version $packageHandle = null; $packageDirectory = null; $packageVersion = null; $p = $input->getArgument('package'); if (is_dir($p) || !$vsh->handle($p)) { $packageDirectory = @realpath($p); if ($packageDirectory === false) { throw new Exception("Unable to find the directory '{$p}'"); } $controllerFile = $packageDirectory . '/' . FILENAME_CONTROLLER; if (!is_file($controllerFile)) { throw new Exception("The directory '{$packageDirectory}' does not seems to contain a valid concrete5 package"); } $controllerContents = $fh->getContents($controllerFile); if ($controllerContents) { $allTokens = @token_get_all($controllerContents); if ($allTokens) { $tokens = array_values(array_filter($allTokens, function ($token) { $keep = true; if (is_array($token)) { switch ($token[0]) { case T_DOC_COMMENT: case T_WHITESPACE: case T_COMMENT: $keep = false; break; } } return $keep; })); // Look for package version for ($i = 0; $i < count($tokens) - 2; ++$i) { if ($packageHandle === null && is_array($tokens[$i + 0]) && $tokens[$i + 0][0] === T_VARIABLE && $tokens[$i + 0][1] === '$pkgHandle' && is_string($tokens[$i + 1]) && $tokens[$i + 1] === '=' && is_array($tokens[$i + 2]) && $tokens[$i + 2][0] === T_CONSTANT_ENCAPSED_STRING) { $packageHandle = @eval('return ' . $tokens[$i + 2][1] . ';'); } if ($packageVersion === null && is_array($tokens[$i + 0]) && $tokens[$i + 0][0] === T_VARIABLE && $tokens[$i + 0][1] === '$pkgVersion' && is_string($tokens[$i + 1]) && $tokens[$i + 1] === '=' && is_array($tokens[$i + 2]) && $tokens[$i + 2][0] === T_CONSTANT_ENCAPSED_STRING) { $packageVersion = @eval('return ' . $tokens[$i + 2][1] . ';'); } } } } if ($packageHandle === null) { $packageHandle = basename($packageDirectory); } } else { foreach (Package::getAvailablePackages(false) as $pkg) { if (strcasecmp($p, $pkg->getPackageHandle()) === 0) { $packageHandle = $pkg->getPackageHandle(); $packageDirectory = $pkg->getPackagePath(); $packageVersion = $pkg->getPackageVersion(); break; } } if ($packageHandle === null) { throw new Exception("Unable to find a package with handle '{$p}'"); } } $packageLanguagesDirectory = $packageDirectory . '/' . DIRNAME_LANGUAGES; // Determine the locales to translate $locales = array(); $localeOption = $input->getOption('locale'); if (in_array('-', $localeOption, true)) { // We don't want any locale } elseif (empty($localeOption)) { // List the currently package locales foreach ($fh->getDirectoryContents($packageLanguagesDirectory) as $item) { if (is_file("{$packageLanguagesDirectory}/{$item}/LC_MESSAGES/messages.mo") || is_file("{$baseDir}/{$item}/LC_MESSAGES/messages.po")) { $locales[] = $item; } } if (empty($locales)) { // Let's use the core locales $locales = Localization::getAvailableInterfaceLanguages(); } } else { // Normalize the locales (eg from it-it to it_IT) foreach ($localeOption as $lo) { $chunks = array(); foreach (explode('_', str_replace('-', '_', $lo)) as $index => $chunk) { if ($index === 0) { // Language (eg zh) $chunks[] = strtolower($chunk); } elseif (strlen($chunk) === 4) { // Script (eg Hans) $chunks[] = ucfirst(strtolower($chunk)); } else { // Territory (eg CN) $chunks[] = strtoupper($chunk); } } $locales[] = implode('_', $chunks); } } // Initialize the master translations file (.pot) $pot = new Translations(); $pot->setHeader('Project-Id-Version', "{$packageHandle} {$packageVersion}"); $pot->setLanguage('en_US'); $pot->setHeader('Report-Msgid-Bugs-To', $input->getOption('contact')); $pot->setHeader('Last-Translator', $input->getOption('translator')); // Parse the package directory $output->writeln('Parsing package contents'); foreach (\C5TL\Parser::getAllParsers() as $parser) { if ($parser->canParseDirectory()) { $output->write('- running parser "' . $parser->getParserName() . '"... '); $parser->parseDirectory($packageDirectory, "packages/{$packageHandle}", $pot, false, $input->getOption('exclude-3rdparty')); $output->writeln('done.'); } } // Save the pot file $output->write('Saving .pot file... '); if (!is_dir($packageLanguagesDirectory)) { @mkdir($packageLanguagesDirectory, 0775, true); if (!is_dir($packageLanguagesDirectory)) { throw new Exception("Unable to create the directory {$packageLanguagesDirectory}"); } } $potFilename = "{$packageLanguagesDirectory}/messages.pot"; if ($pot->toPoFile($potFilename) === false) { throw new Exception("Unable to save the .pot file to {$potFilename}"); } $output->writeln('done.'); // Creating/updating the locale files foreach ($locales as $locale) { $output->writeln("Working on locale {$locale}"); $poDirectory = "{$packageLanguagesDirectory}/{$locale}/LC_MESSAGES"; $po = clone $pot; $po->setLanguage($locale); $poFile = "{$poDirectory}/messages.po"; $moFile = "{$poDirectory}/messages.mo"; if (is_file($poFile)) { $output->write("- reading current .po file... "); $oldPo = Translations::fromPoFile($poFile); $output->writeln('done.'); } elseif (is_file($moFile)) { $output->write("- decompiling current .mo file... "); $oldPo = Translations::fromMoFile($poFile); $output->writeln('done.'); } else { $oldPo = null; } if ($oldPo !== null) { $output->write("- merging translations... "); $po->mergeWith($oldPo, 0); $output->writeln('done.'); } $output->write("- saving .po file... "); if (!is_dir($poDirectory)) { @mkdir($poDirectory, 0775, true); if (!is_dir($poDirectory)) { throw new Exception("Unable to create the directory {$poDirectory}"); } } $po->toPoFile($poFile); $output->writeln('done.'); $output->write("- saving .mo file... "); $po->toMoFile($moFile); $output->writeln('done.'); } } catch (Exception $x) { $output->writeln($x->getMessage()); return 1; } }