TPSection, ... ) */ protected $dbSections = null; /// Constructor public function __construct( Title $title ) { $this->title = $title; } /** * Returns the number of sections in this page. * @return int */ public function countSections() { return count( $this->sections ); } /** * Returns the page template where translatable content is replaced with * placeholders. * @return string */ public function getTemplate() { return $this->template; } /** * Returns the page template where the ugly placeholders are replaced with * section markers. Sections which previously had no number will get one * assigned now. * @return string */ public function getTemplatePretty() { $text = $this->template; $sections = $this->getSectionsForSave(); foreach ( $sections as $ph => $s ) { $text = str_replace( $ph, "", $text ); } return $text; } /** * Gets the sections and assigns section id for new sections * @param int $highest The largest used integer id (Since 2012-08-02) * @return TPSection[] array( string => TPSection, ... ) */ public function getSectionsForSave( $highest = 0 ) { $this->loadFromDatabase(); $sections = $this->sections; foreach ( array_keys( $this->dbSections ) as $key ) { $highest = max( $highest, (int)$key ); } foreach ( $sections as $_ ) { $highest = max( $highest, (int)$_->id ); } foreach ( $sections as $s ) { $s->type = 'old'; if ( $s->id === -1 ) { $s->type = 'new'; $s->id = ++$highest; } else { if ( isset( $this->dbSections[$s->id] ) ) { $storedText = $this->dbSections[$s->id]->text; if ( $s->text !== $storedText ) { $s->type = 'changed'; $s->oldText = $storedText; } } } } return $sections; } /** * Returns list of deleted sections. * @return TPSection[] List of sections indexed by id. array( string => TPsection, ... ) */ public function getDeletedSections() { $sections = $this->getSectionsForSave(); $deleted = $this->dbSections; foreach ( $sections as $s ) { if ( isset( $deleted[$s->id] ) ) { unset( $deleted[$s->id] ); } } return $deleted; } /** * Load section saved in the database. Populates dbSections. */ protected function loadFromDatabase() { if ( $this->dbSections !== null ) { return; } $this->dbSections = []; $db = TranslateUtils::getSafeReadDB(); $tables = 'translate_sections'; $vars = [ 'trs_key', 'trs_text' ]; $conds = [ 'trs_page' => $this->title->getArticleID() ]; $res = $db->select( $tables, $vars, $conds, __METHOD__ ); foreach ( $res as $r ) { $section = new TPSection; $section->id = $r->trs_key; $section->text = $r->trs_text; $section->type = 'db'; $this->dbSections[$r->trs_key] = $section; } } /** * Returns the source page with translation section mark-up added. * * @return string Wikitext. */ public function getSourcePageText() { $text = $this->template; foreach ( $this->sections as $ph => $s ) { $text = str_replace( $ph, $s->getMarkedText(), $text ); } return $text; } /** * Returns translation page with all possible translations replaced in, ugly * translation tags removed and outdated translation marked with a class * mw-translate-fuzzy. * * @param MessageCollection $collection Collection that holds translated messages. * @param bool $showOutdated Whether to show outdated sections, wrapped in a HTML class. * @return string Whole page as wikitext. */ public function getTranslationPageText( $collection, $showOutdated = false ) { $text = $this->template; // The source // For finding the messages $prefix = $this->title->getPrefixedDBkey() . '/'; if ( $collection instanceof MessageCollection ) { $collection->loadTranslations(); if ( $showOutdated ) { $collection->filter( 'hastranslation', false ); } else { $collection->filter( 'translated', false ); } } foreach ( $this->sections as $ph => $s ) { $sectiontext = null; if ( isset( $collection[$prefix . $s->id] ) ) { /** @var TMessage $msg */ $msg = $collection[$prefix . $s->id]; /** @var string|null */ $sectiontext = $msg->translation(); // If translation is fuzzy, $sectiontext must be a string if ( $msg->hasTag( 'fuzzy' ) ) { // We do not ever want to show explicit fuzzy marks in the rendered pages $sectiontext = str_replace( TRANSLATE_FUZZY, '', $sectiontext ); if ( $s->isInline() ) { $sectiontext = "$sectiontext"; } else { // We add new lines around the text to avoid disturbing any mark-up that // has special handling on line start, such as lists. $sectiontext = "
\n$sectiontext\n
"; } } } // Use the original text if no translation is available. // For the source language, this will actually be the source, which // contains variable declarations (tvar) instead of variables ($1). // The getTextWithVariables will convert declarations to normal variables // for us so that the variable substitutions below will also work // for the source language. if ( $sectiontext === null || $sectiontext === $s->getText() ) { $sectiontext = $s->getTextWithVariables(); } // Substitute variables into section text and substitute text into document $sectiontext = strtr( $sectiontext, $s->getVariables() ); $text = str_replace( $ph, $sectiontext, $text ); } $nph = []; $text = TranslatablePage::armourNowiki( $nph, $text ); // Remove translation markup from the template to produce final text $cb = [ __CLASS__, 'replaceTagCb' ]; $text = preg_replace_callback( '~()(.*)()~sU', $cb, $text ); $text = TranslatablePage::unArmourNowiki( $nph, $text ); return $text; } /** * Chops of trailing or preceeding whitespace intelligently to avoid * build up of unintented whitespace. * @param string[] $matches * @return string */ protected static function replaceTagCb( $matches ) { return preg_replace( '~^\n|\n\z~', '', $matches[2] ); } }