summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/Translate/messagegroups/MessageGroupBase.php
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/extensions/Translate/messagegroups/MessageGroupBase.php')
-rw-r--r--www/wiki/extensions/Translate/messagegroups/MessageGroupBase.php452
1 files changed, 452 insertions, 0 deletions
diff --git a/www/wiki/extensions/Translate/messagegroups/MessageGroupBase.php b/www/wiki/extensions/Translate/messagegroups/MessageGroupBase.php
new file mode 100644
index 00000000..665e8203
--- /dev/null
+++ b/www/wiki/extensions/Translate/messagegroups/MessageGroupBase.php
@@ -0,0 +1,452 @@
+<?php
+/**
+ * This file contains a base implementation of managed message groups.
+ *
+ * @file
+ * @author Niklas Laxström
+ * @copyright Copyright © 2010-2013, Niklas Laxström
+ * @license GPL-2.0-or-later
+ */
+
+/**
+ * This class implements some basic functions that wrap around the YAML
+ * message group configurations. These message groups use the FFS classes
+ * and are managed with Special:ManageMessageGroups and
+ * processMessageChanges.php.
+ *
+ * @see https://www.mediawiki.org/wiki/Help:Extension:Translate/Group_configuration
+ * @ingroup MessageGroup
+ */
+abstract class MessageGroupBase implements MessageGroup {
+ protected $conf;
+ protected $namespace;
+ protected $groups;
+
+ /**
+ * @var StringMatcher
+ */
+ protected $mangler;
+
+ protected function __construct() {
+ }
+
+ /**
+ * @param array $conf
+ *
+ * @return MessageGroup
+ */
+ public static function factory( $conf ) {
+ $obj = new $conf['BASIC']['class']();
+ $obj->conf = $conf;
+ $obj->namespace = $obj->parseNamespace();
+
+ return $obj;
+ }
+
+ public function getConfiguration() {
+ return $this->conf;
+ }
+
+ public function getId() {
+ return $this->getFromConf( 'BASIC', 'id' );
+ }
+
+ public function getLabel( IContextSource $context = null ) {
+ return $this->getFromConf( 'BASIC', 'label' );
+ }
+
+ public function getDescription( IContextSource $context = null ) {
+ return $this->getFromConf( 'BASIC', 'description' );
+ }
+
+ public function getIcon() {
+ return $this->getFromConf( 'BASIC', 'icon' );
+ }
+
+ public function getNamespace() {
+ return $this->namespace;
+ }
+
+ public function isMeta() {
+ return $this->getFromConf( 'BASIC', 'meta' );
+ }
+
+ public function getSourceLanguage() {
+ $conf = $this->getFromConf( 'BASIC', 'sourcelanguage' );
+
+ return $conf !== null ? $conf : 'en';
+ }
+
+ public function getDefinitions() {
+ $defs = $this->load( $this->getSourceLanguage() );
+
+ return $defs;
+ }
+
+ protected function getFromConf( $section, $key ) {
+ return $this->conf[$section][$key] ?? null;
+ }
+
+ /**
+ * @return FFS
+ * @throws MWException
+ */
+ public function getFFS() {
+ $class = $this->getFromConf( 'FILES', 'class' );
+
+ if ( $class === null ) {
+ return null;
+ }
+
+ if ( !class_exists( $class ) ) {
+ throw new MWException( "FFS class $class does not exist." );
+ }
+
+ return new $class( $this );
+ }
+
+ public function getChecker() {
+ $class = $this->getFromConf( 'CHECKER', 'class' );
+
+ if ( $class === null ) {
+ return null;
+ }
+
+ if ( !class_exists( $class ) ) {
+ throw new MWException( "Checker class $class does not exist." );
+ }
+
+ $checker = new $class( $this );
+ $checks = $this->getFromConf( 'CHECKER', 'checks' );
+
+ if ( !is_array( $checks ) ) {
+ throw new MWException( "Checker class $class not supplied with proper checks." );
+ }
+
+ foreach ( $checks as $check ) {
+ $checker->addCheck( [ $checker, $check ] );
+ }
+
+ return $checker;
+ }
+
+ public function getMangler() {
+ if ( !isset( $this->mangler ) ) {
+ $class = $this->getFromConf( 'MANGLER', 'class' );
+
+ if ( $class === null ) {
+ $this->mangler = StringMatcher::EmptyMatcher();
+
+ return $this->mangler;
+ }
+
+ if ( !class_exists( $class ) ) {
+ throw new MWException( "Mangler class $class does not exist." );
+ }
+
+ /**
+ * @todo Branch handling, merge with upper branch keys
+ */
+ $this->mangler = new $class();
+ $this->mangler->setConf( $this->conf['MANGLER'] );
+ }
+
+ return $this->mangler;
+ }
+
+ /**
+ * Returns the configured InsertablesSuggester if any.
+ * @since 2013.09
+ * @return CombinedInsertablesSuggester
+ */
+ public function getInsertablesSuggester() {
+ $allClasses = [];
+
+ $class = $this->getFromConf( 'INSERTABLES', 'class' );
+ if ( $class !== null ) {
+ $allClasses[] = $class;
+ }
+
+ $classes = $this->getFromConf( 'INSERTABLES', 'classes' );
+ if ( $classes !== null ) {
+ $allClasses = array_merge( $allClasses, $classes );
+ }
+
+ array_unique( $allClasses, SORT_REGULAR );
+
+ $suggesters = [];
+
+ foreach ( $allClasses as $class ) {
+ if ( !class_exists( $class ) ) {
+ throw new MWException( "InsertablesSuggester class $class does not exist." );
+ }
+
+ $suggesters[] = new $class();
+ }
+
+ return new CombinedInsertablesSuggester( $suggesters );
+ }
+
+ /**
+ * Optimized version of array_keys( $_->getDefinitions() ).
+ * @return array
+ * @since 2012-08-21
+ */
+ public function getKeys() {
+ $cache = new MessageGroupCache( $this, $this->getSourceLanguage() );
+ if ( !$cache->exists() ) {
+ return array_keys( $this->getDefinitions() );
+ } else {
+ return $cache->getKeys();
+ }
+ }
+
+ /**
+ * @param string $code Language code.
+ * @return MessageCollection
+ */
+ public function initCollection( $code ) {
+ $namespace = $this->getNamespace();
+ $messages = [];
+
+ $cache = new MessageGroupCache( $this, $this->getSourceLanguage() );
+ if ( !$cache->exists() ) {
+ wfWarn( "By-passing message group cache for {$this->getId()}" );
+ $messages = $this->getDefinitions();
+ } else {
+ foreach ( $cache->getKeys() as $key ) {
+ $messages[$key] = $cache->get( $key );
+ }
+ }
+
+ $definitions = new MessageDefinitions( $messages, $namespace );
+ $collection = MessageCollection::newFromDefinitions( $definitions, $code );
+ $this->setTags( $collection );
+
+ return $collection;
+ }
+
+ /**
+ * @param string $key Message key
+ * @param string $code Language code
+ * @return string|null
+ */
+ public function getMessage( $key, $code ) {
+ $cache = new MessageGroupCache( $this, $code );
+ if ( $cache->exists() ) {
+ $msg = $cache->get( $key );
+
+ if ( $msg !== false ) {
+ return $msg;
+ }
+
+ // Try harder
+ $nkey = str_replace( ' ', '_', strtolower( $key ) );
+ $keys = $cache->getKeys();
+
+ foreach ( $keys as $k ) {
+ if ( $nkey === str_replace( ' ', '_', strtolower( $k ) ) ) {
+ return $cache->get( $k );
+ }
+ }
+
+ return null;
+ } else {
+ return null;
+ }
+ }
+
+ public function getTags( $type = null ) {
+ if ( $type === null ) {
+ $taglist = [];
+
+ foreach ( $this->getRawTags() as $type => $patterns ) {
+ $taglist[$type] = $this->parseTags( $patterns );
+ }
+
+ return $taglist;
+ } else {
+ return $this->parseTags( $this->getRawTags( $type ) );
+ }
+ }
+
+ protected function parseTags( $patterns ) {
+ $messageKeys = $this->getKeys();
+
+ $matches = [];
+
+ /**
+ * Collect exact keys, no point running them trough string matcher
+ */
+ foreach ( $patterns as $index => $pattern ) {
+ if ( strpos( $pattern, '*' ) === false ) {
+ $matches[] = $pattern;
+ unset( $patterns[$index] );
+ }
+ }
+
+ if ( count( $patterns ) ) {
+ /**
+ * Rest of the keys contain wildcards.
+ */
+ $mangler = new StringMatcher( '', $patterns );
+
+ /**
+ * Use mangler to find messages that match.
+ */
+ foreach ( $messageKeys as $key ) {
+ if ( $mangler->match( $key ) ) {
+ $matches[] = $key;
+ }
+ }
+ }
+
+ return $matches;
+ }
+
+ protected function getRawTags( $type = null ) {
+ if ( !isset( $this->conf['TAGS'] ) ) {
+ return [];
+ }
+
+ $tags = $this->conf['TAGS'];
+ if ( !$type ) {
+ return $tags;
+ }
+
+ if ( isset( $tags[$type] ) ) {
+ return $tags[$type];
+ }
+
+ return [];
+ }
+
+ protected function setTags( MessageCollection $collection ) {
+ foreach ( $this->getTags() as $type => $tags ) {
+ $collection->setTags( $type, $tags );
+ }
+ }
+
+ protected function parseNamespace() {
+ $ns = $this->getFromConf( 'BASIC', 'namespace' );
+
+ if ( is_int( $ns ) ) {
+ return $ns;
+ }
+
+ if ( defined( $ns ) ) {
+ return constant( $ns );
+ }
+
+ global $wgContLang;
+
+ $index = $wgContLang->getNsIndex( $ns );
+
+ if ( !$index ) {
+ throw new MWException( "No valid namespace defined, got $ns." );
+ }
+
+ return $index;
+ }
+
+ protected function isSourceLanguage( $code ) {
+ return $code === $this->getSourceLanguage();
+ }
+
+ /**
+ * @deprecated Use getMessageGroupStates
+ */
+ public function getWorkflowConfiguration() {
+ global $wgTranslateWorkflowStates;
+ if ( !$wgTranslateWorkflowStates ) {
+ // Not configured
+ $conf = [];
+ } else {
+ $conf = $wgTranslateWorkflowStates;
+ }
+
+ return $conf;
+ }
+
+ /**
+ * Get the message group workflow state configuration.
+ * @return MessageGroupStates
+ */
+ public function getMessageGroupStates() {
+ // @todo Replace deprecated call.
+ $conf = $this->getWorkflowConfiguration();
+
+ Hooks::run( 'Translate:modifyMessageGroupStates', [ $this->getId(), &$conf ] );
+
+ return new MessageGroupStates( $conf );
+ }
+
+ /**
+ * Get all the translatable languages for a group, considering the whitelisting
+ * and blacklisting.
+ * @return array|null The language codes as array keys.
+ */
+ public function getTranslatableLanguages() {
+ global $wgTranslateBlacklist;
+
+ $groupConfiguration = $this->getConfiguration();
+ if ( !isset( $groupConfiguration['LANGUAGES'] ) ) {
+ // No LANGUAGES section in the configuration.
+ return null;
+ }
+
+ $codes = array_flip( array_keys( TranslateUtils::getLanguageNames( null ) ) );
+
+ $lists = $groupConfiguration['LANGUAGES'];
+ if ( isset( $lists['blacklist'] ) ) {
+ $blacklist = $lists['blacklist'];
+ if ( $blacklist === '*' ) {
+ // All languages blacklisted
+ $codes = [];
+ } elseif ( is_array( $blacklist ) ) {
+ foreach ( $blacklist as $code ) {
+ unset( $codes[$code] );
+ }
+ }
+ } else {
+ // Treat lack of explicit blacklist the same as blacklisting everything. This way,
+ // when one defines only whitelist, it means that only those languages are allowed.
+ $codes = [];
+ }
+
+ // DWIM with $wgTranslateBlacklist, e.g. languages in that list should not unexpectedly
+ // be enabled when a whitelist is used to whitelist any language.
+ $checks = [ $this->getId(), strtok( $this->getId(), '-' ), '*' ];
+ foreach ( $checks as $check ) {
+ if ( isset( $wgTranslateBlacklist[ $check ] ) ) {
+ foreach ( array_keys( $wgTranslateBlacklist[ $check ] ) as $blacklistedCode ) {
+ unset( $codes[ $blacklistedCode ] );
+ }
+ }
+ }
+
+ if ( isset( $lists['whitelist'] ) ) {
+ $whitelist = $lists['whitelist'];
+ if ( $whitelist === '*' ) {
+ // All languages whitelisted (except $wgTranslateBlacklist)
+ return null;
+ } elseif ( is_array( $whitelist ) ) {
+ foreach ( $whitelist as $code ) {
+ $codes[$code] = true;
+ }
+ }
+ }
+
+ return $codes;
+ }
+
+ /**
+ * List of available message types mapped to the classes
+ * implementing them. Default implementation (all).
+ *
+ * @return array
+ */
+ public function getTranslationAids() {
+ return TranslationAid::getTypes();
+ }
+}