class PoDatabaseWriter

Same name and namespace in other branches
  1. 8.9.x core/modules/locale/src/PoDatabaseWriter.php \Drupal\locale\PoDatabaseWriter
  2. 10 core/modules/locale/src/PoDatabaseWriter.php \Drupal\locale\PoDatabaseWriter
  3. 11.x core/modules/locale/src/PoDatabaseWriter.php \Drupal\locale\PoDatabaseWriter

Gettext PO writer working with the locale module database.

Hierarchy

Expanded class hierarchy of PoDatabaseWriter

File

core/modules/locale/src/PoDatabaseWriter.php, line 13

Namespace

Drupal\locale
View source
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))) {
                [
                    $nplurals,
                    $formula,
                ] = $p;
                \Drupal::service('locale.plural.formula')->setPluralFormula($langcode, $nplurals, $formula);
            }
        }
    }
    
    /**
     * {@inheritdoc}
     */
    public function writeItem(PoItem $item) {
        if ($item->isPlural()) {
            $item->setSource(implode(PoItem::DELIMITER, $item->getSource()));
            $item->setTranslation(implode(PoItem::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;
        }
    }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title
PoDatabaseWriter::$header private property Header of the po file written to the database.
PoDatabaseWriter::$langcode private property Language code of the language being written to the database.
PoDatabaseWriter::$options private property An associative array indicating what data should be overwritten, if any.
PoDatabaseWriter::$report private property Associative array summarizing the number of changes done.
PoDatabaseWriter::getHeader public function Get header metadata. Overrides PoMetadataInterface::getHeader
PoDatabaseWriter::getLangcode public function Get language code. Overrides PoMetadataInterface::getLangcode
PoDatabaseWriter::getOptions public function Get the options used by the writer.
PoDatabaseWriter::getReport public function Get the report of the write operations.
PoDatabaseWriter::importString private function Imports one string into the database.
PoDatabaseWriter::setHeader public function Implements Drupal\Component\Gettext\PoMetadataInterface::setHeader(). Overrides PoMetadataInterface::setHeader
PoDatabaseWriter::setLangcode public function Set language code. Overrides PoMetadataInterface::setLangcode
PoDatabaseWriter::setOptions public function Set the options for the current writer.
PoDatabaseWriter::setReport public function Set the report array of write operations.
PoDatabaseWriter::writeItem public function Writes the given item. Overrides PoWriterInterface::writeItem
PoDatabaseWriter::writeItems public function Writes all or the given amount of items. Overrides PoWriterInterface::writeItems
PoDatabaseWriter::__construct public function Constructor, initialize reporting array.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.