Mercurial > hg > cmmr2012-drupal-site
diff core/modules/locale/src/PoDatabaseWriter.php @ 0:c75dbcec494b
Initial commit from drush-created site
author | Chris Cannam |
---|---|
date | Thu, 05 Jul 2018 14:24:15 +0000 |
parents | |
children | 12f9dff5fda9 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/modules/locale/src/PoDatabaseWriter.php Thu Jul 05 14:24:15 2018 +0000 @@ -0,0 +1,289 @@ +<?php + +namespace Drupal\locale; + +use Drupal\Component\Gettext\PoHeader; +use Drupal\Component\Gettext\PoItem; +use Drupal\Component\Gettext\PoReaderInterface; +use Drupal\Component\Gettext\PoWriterInterface; + +/** + * Gettext PO writer working with the locale module database. + */ +class PoDatabaseWriter implements PoWriterInterface { + + /** + * An associative array indicating what data should be overwritten, if any. + * + * Elements of the array: + * - overwrite_options + * - not_customized: boolean indicating that not customized strings should + * be overwritten. + * - customized: boolean indicating that customized strings should be + * overwritten. + * - customized: the strings being imported should be saved as customized. + * One of LOCALE_CUSTOMIZED or LOCALE_NOT_CUSTOMIZED. + * + * @var array + */ + private $options; + + /** + * Language code of the language being written to the database. + * + * @var string + */ + private $langcode; + + /** + * Header of the po file written to the database. + * + * @var \Drupal\Component\Gettext\PoHeader + */ + private $header; + + /** + * Associative array summarizing the number of changes done. + * + * Keys for the array: + * - additions: number of source strings newly added + * - updates: number of translations updated + * - deletes: number of translations deleted + * - skips: number of strings skipped due to disallowed HTML + * + * @var array + */ + private $report; + + /** + * Constructor, initialize reporting array. + */ + public function __construct() { + $this->setReport(); + } + + /** + * {@inheritdoc} + */ + public function getLangcode() { + return $this->langcode; + } + + /** + * {@inheritdoc} + */ + public function setLangcode($langcode) { + $this->langcode = $langcode; + } + + /** + * Get the report of the write operations. + */ + public function getReport() { + return $this->report; + } + + /** + * Set the report array of write operations. + * + * @param array $report + * Associative array with result information. + */ + public function setReport($report = []) { + $report += [ + 'additions' => 0, + 'updates' => 0, + 'deletes' => 0, + 'skips' => 0, + 'strings' => [], + ]; + $this->report = $report; + } + + /** + * Get the options used by the writer. + */ + public function getOptions() { + return $this->options; + } + + /** + * Set the options for the current writer. + * + * @param array $options + * An associative array containing: + * - overwrite_options: An array of options. Each option contains: + * - not_customized: Boolean indicating that not customized strings should + * be overwritten. + * - customized: Boolean indicating that customized strings should be + * overwritten. + * - customized: The strings being imported should be saved as customized. + * One of LOCALE_CUSTOMIZED or LOCALE_NOT_CUSTOMIZED. + */ + public function setOptions(array $options) { + if (!isset($options['overwrite_options'])) { + $options['overwrite_options'] = []; + } + $options['overwrite_options'] += [ + 'not_customized' => FALSE, + 'customized' => FALSE, + ]; + $options += [ + 'customized' => LOCALE_NOT_CUSTOMIZED, + ]; + $this->options = $options; + } + + /** + * {@inheritdoc} + */ + public function getHeader() { + return $this->header; + } + + /** + * Implements Drupal\Component\Gettext\PoMetadataInterface::setHeader(). + * + * Sets the header and configure Drupal accordingly. + * + * Before being able to process the given header we need to know in what + * context this database write is done. For this the options must be set. + * + * A langcode is required to set the current header's PluralForm. + * + * @param \Drupal\Component\Gettext\PoHeader $header + * Header metadata. + * + * @throws Exception + */ + public function setHeader(PoHeader $header) { + $this->header = $header; + $locale_plurals = \Drupal::state()->get('locale.translation.plurals') ?: []; + + // Check for options. + $options = $this->getOptions(); + if (empty($options)) { + throw new \Exception('Options should be set before assigning a PoHeader.'); + } + $overwrite_options = $options['overwrite_options']; + + // Check for langcode. + $langcode = $this->langcode; + if (empty($langcode)) { + throw new \Exception('Langcode should be set before assigning a PoHeader.'); + } + + if (array_sum($overwrite_options) || empty($locale_plurals[$langcode]['plurals'])) { + // Get and store the plural formula if available. + $plural = $header->getPluralForms(); + if (isset($plural) && $p = $header->parsePluralForms($plural)) { + list($nplurals, $formula) = $p; + \Drupal::service('locale.plural.formula')->setPluralFormula($langcode, $nplurals, $formula); + } + } + } + + /** + * {@inheritdoc} + */ + public function writeItem(PoItem $item) { + if ($item->isPlural()) { + $item->setSource(implode(LOCALE_PLURAL_DELIMITER, $item->getSource())); + $item->setTranslation(implode(LOCALE_PLURAL_DELIMITER, $item->getTranslation())); + } + $this->importString($item); + } + + /** + * {@inheritdoc} + */ + public function writeItems(PoReaderInterface $reader, $count = -1) { + $forever = $count == -1; + while (($count-- > 0 || $forever) && ($item = $reader->readItem())) { + $this->writeItem($item); + } + } + + /** + * Imports one string into the database. + * + * @param \Drupal\Component\Gettext\PoItem $item + * The item being imported. + * + * @return int + * The string ID of the existing string modified or the new string added. + */ + private function importString(PoItem $item) { + // Initialize overwrite options if not set. + $this->options['overwrite_options'] += [ + 'not_customized' => FALSE, + 'customized' => FALSE, + ]; + $overwrite_options = $this->options['overwrite_options']; + $customized = $this->options['customized']; + + $context = $item->getContext(); + $source = $item->getSource(); + $translation = $item->getTranslation(); + + // Look up the source string and any existing translation. + $strings = \Drupal::service('locale.storage')->getTranslations([ + 'language' => $this->langcode, + 'source' => $source, + 'context' => $context, + ]); + $string = reset($strings); + + if (!empty($translation)) { + // Skip this string unless it passes a check for dangerous code. + if (!locale_string_is_safe($translation)) { + \Drupal::logger('locale')->error('Import of string "%string" was skipped because of disallowed or malformed HTML.', ['%string' => $translation]); + $this->report['skips']++; + return 0; + } + elseif ($string) { + $string->setString($translation); + if ($string->isNew()) { + // No translation in this language. + $string->setValues([ + 'language' => $this->langcode, + 'customized' => $customized, + ]); + $string->save(); + $this->report['additions']++; + } + elseif ($overwrite_options[$string->customized ? 'customized' : 'not_customized']) { + // Translation exists, only overwrite if instructed. + $string->customized = $customized; + $string->save(); + $this->report['updates']++; + } + $this->report['strings'][] = $string->getId(); + return $string->lid; + } + else { + // No such source string in the database yet. + $string = \Drupal::service('locale.storage')->createString(['source' => $source, 'context' => $context]) + ->save(); + \Drupal::service('locale.storage')->createTranslation([ + 'lid' => $string->getId(), + 'language' => $this->langcode, + 'translation' => $translation, + 'customized' => $customized, + ])->save(); + + $this->report['additions']++; + $this->report['strings'][] = $string->getId(); + return $string->lid; + } + } + elseif ($string && !$string->isNew() && $overwrite_options[$string->customized ? 'customized' : 'not_customized']) { + // Empty translation, remove existing if instructed. + $string->delete(); + $this->report['deletes']++; + $this->report['strings'][] = $string->lid; + return $string->lid; + } + } + +}