Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
DatabaseTtmServer.php
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\TtmServer;
5
8use MediaWiki\MediaWikiServices;
9use MediaWiki\Title\Title;
10use MediaWiki\WikiMap\WikiMap;
11use Wikimedia\Rdbms\DBQueryError;
12use Wikimedia\Rdbms\IDatabase;
13use Wikimedia\Rdbms\IResultWrapper;
14
23 private array $sids;
24
25 private function getDB( int $mode = DB_REPLICA ): IDatabase {
26 return MediaWikiServices::getInstance()->getDBLoadBalancer()->getConnection(
27 $mode, 'ttmserver', $this->config['database']
28 );
29 }
30
31 public function update( MessageHandle $handle, ?string $targetText ): bool {
32 if ( !$handle->isValid() || $handle->getCode() === '' ) {
33 return false;
34 }
35
36 $mKey = $handle->getKey();
37 $group = $handle->getGroup();
38 $targetLanguage = $handle->getCode();
39 $sourceLanguage = $group->getSourceLanguage();
40
41 // Skip definitions to not slow down mass imports etc.
42 // These will be added when the first translation is made
43 if ( $targetLanguage === $sourceLanguage ) {
44 return false;
45 }
46
47 $definition = $group->getMessage( $mKey, $sourceLanguage );
48 if ( !is_string( $definition ) || !strlen( trim( $definition ) ) ) {
49 return false;
50 }
51
52 $context = Title::makeTitle( $handle->getTitle()->getNamespace(), $mKey );
53 $dbw = $this->getDB( DB_PRIMARY );
54 /* Check that the definition exists and fetch the sid. If not, add
55 * the definition and retrieve the sid. If the definition changes,
56 * we will create a new entry - otherwise we could at some point
57 * get suggestions which do not match the original definition any
58 * longer. The old translations are still kept until purged by
59 * rerunning the bootstrap script. */
60 $sid = $dbw->newSelectQueryBuilder()
61 ->select( 'tms_sid' )
62 ->from( 'translate_tms' )
63 ->where( [
64 'tms_context' => $context->getPrefixedText(),
65 'tms_text' => $definition,
66 ] )
67 ->caller( __METHOD__ )
68 ->fetchField();
69 if ( $sid === false ) {
70 $sid = $this->insertSource( $context, $sourceLanguage, $definition );
71 }
72
73 // Delete old translations for this message if any. Could also use replace
74 $deleteConditions = [
75 'tmt_sid' => $sid,
76 'tmt_lang' => $targetLanguage,
77 ];
78 $dbw->newDeleteQueryBuilder()
79 ->deleteFrom( 'translate_tmt' )
80 ->where( $deleteConditions )
81 ->caller( __METHOD__ )
82 ->execute();
83
84 // Insert the new translation
85 if ( $targetText !== null ) {
86 $row = $deleteConditions + [
87 'tmt_text' => $targetText,
88 ];
89
90 $dbw->newInsertQueryBuilder()
91 ->insertInto( 'translate_tmt' )
92 ->row( $row )
93 ->caller( __METHOD__ )
94 ->execute();
95 }
96
97 return true;
98 }
99
100 private function insertSource( Title $context, string $sourceLanguage, string $text ): int {
101 $dbw = $this->getDB( DB_PRIMARY );
102 $dbw->newInsertQueryBuilder()
103 ->insertInto( 'translate_tms' )
104 ->row( [
105 'tms_lang' => $sourceLanguage,
106 'tms_len' => mb_strlen( $text ),
107 'tms_text' => $text,
108 'tms_context' => $context->getPrefixedText(),
109 ] )
110 ->caller( __METHOD__ )
111 ->execute();
112 $sid = $dbw->insertId();
113
114 $fulltext = $this->filterForFulltext( $sourceLanguage, $text );
115 if ( count( $fulltext ) ) {
116 $dbw->newInsertQueryBuilder()
117 ->insertInto( 'translate_tmf' )
118 ->row( [
119 'tmf_sid' => $sid,
120 'tmf_text' => implode( ' ', $fulltext ),
121 ] )
122 ->caller( __METHOD__ )
123 ->execute();
124 }
125
126 return $sid;
127 }
128
130 protected function filterForFulltext( string $languageCode, string $input ): array {
131 $lang = MediaWikiServices::getInstance()->getLanguageFactory()->getLanguage( $languageCode );
132
133 $text = preg_replace( '/[^[:alnum:]]/u', ' ', $input );
134 $text = $lang->segmentByWord( $text );
135 $text = $lang->lc( $text );
136 $segments = preg_split( '/\s+/', $text, -1, PREG_SPLIT_NO_EMPTY );
137 if ( count( $segments ) < 4 ) {
138 return [];
139 }
140
141 foreach ( $segments as $i => $segment ) {
142 // Yes strlen
143 $len = strlen( $segment );
144 if ( $len < 4 || $len > 15 ) {
145 unset( $segments[$i] );
146 }
147 }
148
149 return array_slice( array_unique( $segments ), 0, 10 );
150 }
151
152 public function beginBootstrap(): void {
153 $dbw = $this->getDB( DB_PRIMARY );
154 $dbw->newDeleteQueryBuilder()
155 ->deleteFrom( 'translate_tms' )
156 ->where( '*' )
157 ->caller( __METHOD__ )
158 ->execute();
159 $dbw->newDeleteQueryBuilder()
160 ->deleteFrom( 'translate_tmt' )
161 ->where( '*' )
162 ->caller( __METHOD__ )
163 ->execute();
164 $dbw->newDeleteQueryBuilder()
165 ->deleteFrom( 'translate_tmf' )
166 ->where( '*' )
167 ->caller( __METHOD__ )
168 ->execute();
169 $table = $dbw->tableName( 'translate_tmf' );
170 try {
171 $dbw->query( "DROP INDEX tmf_text ON $table", __METHOD__ );
172 } catch ( DBQueryError $e ) {
173 // Perhaps the script was aborted before it got
174 // chance to add the index back.
175 }
176 }
177
178 public function beginBatch(): void {
179 $this->sids = [];
180 }
181
182 public function batchInsertDefinitions( array $batch ): void {
183 $mwInstance = MediaWikiServices::getInstance();
184 $titleFactory = $mwInstance->getTitleFactory();
185 foreach ( $batch as $key => $item ) {
186 [ $handle, $language, $text ] = $item;
187 $context = $titleFactory->makeTitle( $handle->getTitle()->getNamespace(), $handle->getKey() );
188 $this->sids[$key] = $this->insertSource( $context, $language, $text );
189 }
190
191 $mwInstance->getDBLoadBalancerFactory()->waitForReplication( [ 'ifWritesSince' => 10 ] );
192 }
193
194 public function batchInsertTranslations( array $batch ): void {
195 if ( $batch === [] ) {
196 return;
197 }
198 $rows = [];
199 foreach ( $batch as $key => $data ) {
200 [ , $language, $text ] = $data;
201 $rows[] = [
202 'tmt_sid' => $this->sids[$key],
203 'tmt_lang' => $language,
204 'tmt_text' => $text,
205 ];
206 }
207
208 $dbw = $this->getDB( DB_PRIMARY );
209 $dbw->newInsertQueryBuilder()
210 ->insertInto( 'translate_tmt' )
211 ->rows( $rows )
212 ->caller( __METHOD__ )
213 ->execute();
214
215 MediaWikiServices::getInstance()
216 ->getDBLoadBalancerFactory()
217 ->waitForReplication( [ 'ifWritesSince' => 10 ] );
218 }
219
220 public function endBatch(): void {
221 }
222
223 public function endBootstrap(): void {
224 $dbw = $this->getDB( DB_PRIMARY );
225 $table = $dbw->tableName( 'translate_tmf' );
226 $dbw->query( "CREATE FULLTEXT INDEX tmf_text ON $table (tmf_text)", __METHOD__ );
227 }
228
229 /* Reading interface */
230
231 public function isLocalSuggestion( array $suggestion ): bool {
232 return true;
233 }
234
235 public function expandLocation( array $suggestion ): string {
236 return Title::newFromText( $suggestion['location'] )->getCanonicalURL();
237 }
238
239 public function query( string $sourceLanguage, string $targetLanguage, string $text ): array {
240 // Calculate the bounds of the string length which are able
241 // to satisfy the cutoff percentage in edit distance.
242 $len = mb_strlen( $text );
243 $min = ceil( max( $len * $this->config['cutoff'], 2 ) );
244 $max = floor( $len / $this->config['cutoff'] );
245
246 // We could use fulltext index to narrow the results further
247 $dbr = $this->getDB();
248 $tables = [ 'translate_tmt', 'translate_tms' ];
249 $fields = [ 'tms_context', 'tms_text', 'tmt_lang', 'tmt_text' ];
250
251 $conditions = [
252 'tms_lang' => $sourceLanguage,
253 'tmt_lang' => $targetLanguage,
254 "tms_len BETWEEN $min AND $max",
255 'tms_sid = tmt_sid',
256 ];
257
258 $fulltext = $this->filterForFulltext( $sourceLanguage, $text );
259 if ( $fulltext ) {
260 $tables[] = 'translate_tmf';
261 $list = implode( ' ', $fulltext );
262 $conditions[] = 'tmf_sid = tmt_sid';
263 $conditions[] = "MATCH(tmf_text) AGAINST( '$list' )";
264 }
265
266 $res = $dbr->newSelectQueryBuilder()
267 ->tables( $tables )
268 ->select( $fields )
269 ->where( $conditions )
270 ->caller( __METHOD__ )
271 ->fetchResultSet();
272
273 return $this->processQueryResults( $res, $text, $targetLanguage );
274 }
275
276 private function processQueryResults( IResultWrapper $res, string $text, string $targetLanguage ): array {
277 $timeLimit = microtime( true ) + 5;
278
279 $lenA = mb_strlen( $text );
280 $results = [];
281 $stringComparator = new EditDistanceStringComparator();
282 foreach ( $res as $row ) {
283 if ( microtime( true ) > $timeLimit ) {
284 // Having no suggestions is better than preventing translation
285 // altogether by timing out the request :(
286 break;
287 }
288
289 $a = $text;
290 $b = $row->tms_text;
291 $lenB = mb_strlen( $b );
292 $len = min( $lenA, $lenB );
293 if ( $len > 600 ) {
294 // two strings of length 1500 ~ 10s
295 // two strings of length 2250 ~ 30s
296 $dist = $len;
297 } else {
298 $dist = $stringComparator->levenshtein( $a, $b, $lenA, $lenB );
299 }
300 $quality = 1 - ( $dist * 0.9 / $len );
301
302 if ( $quality >= $this->config['cutoff'] ) {
303 $results[] = [
304 'source' => $row->tms_text,
305 'target' => $row->tmt_text,
306 'context' => $row->tms_context,
307 'location' => $row->tms_context . '/' . $targetLanguage,
308 'quality' => $quality,
309 'wiki' => $row->tms_wiki ?? WikiMap::getCurrentWikiId(),
310 ];
311 }
312 }
313
314 return TTMServer::sortSuggestions( $results );
315 }
316
317 public function setDoReIndex(): void {
318 }
319}
return[ 'Translate:AggregateGroupManager'=> static function(MediaWikiServices $services):AggregateGroupManager { return new AggregateGroupManager($services->getTitleFactory(), $services->get( 'Translate:MessageGroupMetadata'));}, 'Translate:AggregateGroupMessageGroupFactory'=> static function(MediaWikiServices $services):AggregateGroupMessageGroupFactory { return new AggregateGroupMessageGroupFactory($services->get( 'Translate:MessageGroupMetadata'));}, 'Translate:ConfigHelper'=> static function():ConfigHelper { return new ConfigHelper();}, 'Translate:CsvTranslationImporter'=> static function(MediaWikiServices $services):CsvTranslationImporter { return new CsvTranslationImporter( $services->getWikiPageFactory());}, 'Translate:EntitySearch'=> static function(MediaWikiServices $services):EntitySearch { return new EntitySearch($services->getMainWANObjectCache(), $services->getCollationFactory() ->makeCollation( 'uca-default-u-kn'), MessageGroups::singleton(), $services->getNamespaceInfo(), $services->get( 'Translate:MessageIndex'), $services->getTitleParser(), $services->getTitleFormatter());}, 'Translate:ExternalMessageSourceStateComparator'=> static function(MediaWikiServices $services):ExternalMessageSourceStateComparator { return new ExternalMessageSourceStateComparator(new SimpleStringComparator(), $services->getRevisionLookup(), $services->getPageStore());}, 'Translate:ExternalMessageSourceStateImporter'=> static function(MediaWikiServices $services):ExternalMessageSourceStateImporter { return new ExternalMessageSourceStateImporter($services->get( 'Translate:GroupSynchronizationCache'), $services->getJobQueueGroup(), LoggerFactory::getInstance(LogNames::GROUP_SYNCHRONIZATION), $services->get( 'Translate:MessageIndex'), $services->getTitleFactory(), $services->get( 'Translate:MessageGroupSubscription'), new ServiceOptions(ExternalMessageSourceStateImporter::CONSTRUCTOR_OPTIONS, $services->getMainConfig()));}, 'Translate:FileBasedMessageGroupFactory'=> static function(MediaWikiServices $services):FileBasedMessageGroupFactory { return new FileBasedMessageGroupFactory(new MessageGroupConfigurationParser(), new ServiceOptions(FileBasedMessageGroupFactory::SERVICE_OPTIONS, $services->getMainConfig()),);}, 'Translate:FileFormatFactory'=> static function(MediaWikiServices $services):FileFormatFactory { return new FileFormatFactory( $services->getObjectFactory());}, 'Translate:GroupSynchronizationCache'=> static function(MediaWikiServices $services):GroupSynchronizationCache { return new GroupSynchronizationCache( $services->get( 'Translate:PersistentCache'));}, 'Translate:HookDefinedMessageGroupFactory'=> static function(MediaWikiServices $services):HookDefinedMessageGroupFactory { return new HookDefinedMessageGroupFactory( $services->get( 'Translate:HookRunner'));}, 'Translate:HookRunner'=> static function(MediaWikiServices $services):HookRunner { return new HookRunner( $services->getHookContainer());}, 'Translate:MessageBundleDependencyPurger'=> static function(MediaWikiServices $services):MessageBundleDependencyPurger { return new MessageBundleDependencyPurger( $services->get( 'Translate:TranslatableBundleFactory'));}, 'Translate:MessageBundleMessageGroupFactory'=> static function(MediaWikiServices $services):MessageBundleMessageGroupFactory { return new MessageBundleMessageGroupFactory($services->get( 'Translate:MessageGroupMetadata'), new ServiceOptions(MessageBundleMessageGroupFactory::SERVICE_OPTIONS, $services->getMainConfig()),);}, 'Translate:MessageBundleStore'=> static function(MediaWikiServices $services):MessageBundleStore { return new MessageBundleStore($services->get( 'Translate:RevTagStore'), $services->getJobQueueGroup(), $services->getLanguageNameUtils(), $services->get( 'Translate:MessageIndex'), $services->get( 'Translate:MessageGroupMetadata'));}, 'Translate:MessageBundleTranslationLoader'=> static function(MediaWikiServices $services):MessageBundleTranslationLoader { return new MessageBundleTranslationLoader( $services->getLanguageFallback());}, 'Translate:MessageGroupMetadata'=> static function(MediaWikiServices $services):MessageGroupMetadata { return new MessageGroupMetadata( $services->getConnectionProvider());}, 'Translate:MessageGroupReviewStore'=> static function(MediaWikiServices $services):MessageGroupReviewStore { return new MessageGroupReviewStore($services->getConnectionProvider(), $services->get( 'Translate:HookRunner'));}, 'Translate:MessageGroupStatsTableFactory'=> static function(MediaWikiServices $services):MessageGroupStatsTableFactory { return new MessageGroupStatsTableFactory($services->get( 'Translate:ProgressStatsTableFactory'), $services->getLinkRenderer(), $services->get( 'Translate:MessageGroupReviewStore'), $services->get( 'Translate:MessageGroupMetadata'), $services->getMainConfig() ->get( 'TranslateWorkflowStates') !==false);}, 'Translate:MessageGroupSubscription'=> static function(MediaWikiServices $services):MessageGroupSubscription { return new MessageGroupSubscription($services->get( 'Translate:MessageGroupSubscriptionStore'), $services->getJobQueueGroup(), $services->getUserIdentityLookup(), LoggerFactory::getInstance(LogNames::GROUP_SUBSCRIPTION), new ServiceOptions(MessageGroupSubscription::CONSTRUCTOR_OPTIONS, $services->getMainConfig()));}, 'Translate:MessageGroupSubscriptionHookHandler'=> static function(MediaWikiServices $services):MessageGroupSubscriptionHookHandler { return new MessageGroupSubscriptionHookHandler($services->get( 'Translate:MessageGroupSubscription'), $services->getUserFactory());}, 'Translate:MessageGroupSubscriptionStore'=> static function(MediaWikiServices $services):MessageGroupSubscriptionStore { return new MessageGroupSubscriptionStore( $services->getConnectionProvider());}, 'Translate:MessageIndex'=> static function(MediaWikiServices $services):MessageIndex { $params=(array) $services->getMainConfig() ->get( 'TranslateMessageIndex');$class=array_shift( $params);$implementationMap=['HashMessageIndex'=> HashMessageIndex::class, 'CDBMessageIndex'=> CDBMessageIndex::class, 'DatabaseMessageIndex'=> DatabaseMessageIndex::class, 'hash'=> HashMessageIndex::class, 'cdb'=> CDBMessageIndex::class, 'database'=> DatabaseMessageIndex::class,];$messageIndexStoreClass=$implementationMap[$class] ?? $implementationMap['database'];return new MessageIndex(new $messageIndexStoreClass, $services->getMainWANObjectCache(), $services->getJobQueueGroup(), $services->get( 'Translate:HookRunner'), LoggerFactory::getInstance(LogNames::MAIN), $services->getMainObjectStash(), $services->getConnectionProvider(), new ServiceOptions(MessageIndex::SERVICE_OPTIONS, $services->getMainConfig()),);}, 'Translate:MessagePrefixStats'=> static function(MediaWikiServices $services):MessagePrefixStats { return new MessagePrefixStats( $services->getTitleParser());}, 'Translate:ParsingPlaceholderFactory'=> static function():ParsingPlaceholderFactory { return new ParsingPlaceholderFactory();}, 'Translate:PersistentCache'=> static function(MediaWikiServices $services):PersistentCache { return new PersistentDatabaseCache($services->getConnectionProvider(), $services->getJsonCodec());}, 'Translate:ProgressStatsTableFactory'=> static function(MediaWikiServices $services):ProgressStatsTableFactory { return new ProgressStatsTableFactory($services->getLinkRenderer(), $services->get( 'Translate:ConfigHelper'), $services->get( 'Translate:MessageGroupMetadata'));}, 'Translate:RevTagStore'=> static function(MediaWikiServices $services):RevTagStore { return new RevTagStore( $services->getConnectionProvider());}, 'Translate:SubpageListBuilder'=> static function(MediaWikiServices $services):SubpageListBuilder { return new SubpageListBuilder($services->get( 'Translate:TranslatableBundleFactory'), $services->getLinkBatchFactory());}, 'Translate:TranslatableBundleDeleter'=> static function(MediaWikiServices $services):TranslatableBundleDeleter { return new TranslatableBundleDeleter($services->getMainObjectStash(), $services->getJobQueueGroup(), $services->get( 'Translate:SubpageListBuilder'), $services->get( 'Translate:TranslatableBundleFactory'));}, 'Translate:TranslatableBundleExporter'=> static function(MediaWikiServices $services):TranslatableBundleExporter { return new TranslatableBundleExporter($services->get( 'Translate:SubpageListBuilder'), $services->getWikiExporterFactory(), $services->getConnectionProvider());}, 'Translate:TranslatableBundleFactory'=> static function(MediaWikiServices $services):TranslatableBundleFactory { return new TranslatableBundleFactory($services->get( 'Translate:TranslatablePageStore'), $services->get( 'Translate:MessageBundleStore'));}, 'Translate:TranslatableBundleImporter'=> static function(MediaWikiServices $services):TranslatableBundleImporter { return new TranslatableBundleImporter($services->getWikiImporterFactory(), $services->get( 'Translate:TranslatablePageParser'), $services->getRevisionLookup(), $services->getNamespaceInfo(), $services->getTitleFactory(), $services->getFormatterFactory());}, 'Translate:TranslatableBundleMover'=> static function(MediaWikiServices $services):TranslatableBundleMover { return new TranslatableBundleMover($services->getMovePageFactory(), $services->getJobQueueGroup(), $services->getLinkBatchFactory(), $services->get( 'Translate:TranslatableBundleFactory'), $services->get( 'Translate:SubpageListBuilder'), $services->getConnectionProvider(), $services->getObjectCacheFactory(), $services->getMainConfig() ->get( 'TranslatePageMoveLimit'));}, 'Translate:TranslatableBundleStatusStore'=> static function(MediaWikiServices $services):TranslatableBundleStatusStore { return new TranslatableBundleStatusStore($services->getConnectionProvider() ->getPrimaryDatabase(), $services->getCollationFactory() ->makeCollation( 'uca-default-u-kn'), $services->getDBLoadBalancer() ->getMaintenanceConnectionRef(DB_PRIMARY));}, 'Translate:TranslatablePageMarker'=> static function(MediaWikiServices $services):TranslatablePageMarker { return new TranslatablePageMarker($services->getConnectionProvider(), $services->getJobQueueGroup(), $services->getLinkRenderer(), MessageGroups::singleton(), $services->get( 'Translate:MessageIndex'), $services->getTitleFormatter(), $services->getTitleParser(), $services->get( 'Translate:TranslatablePageParser'), $services->get( 'Translate:TranslatablePageStore'), $services->get( 'Translate:TranslatablePageStateStore'), $services->get( 'Translate:TranslationUnitStoreFactory'), $services->get( 'Translate:MessageGroupMetadata'), $services->getWikiPageFactory(), $services->get( 'Translate:TranslatablePageView'), $services->get( 'Translate:MessageGroupSubscription'), $services->getFormatterFactory());}, 'Translate:TranslatablePageMessageGroupFactory'=> static function(MediaWikiServices $services):TranslatablePageMessageGroupFactory { return new TranslatablePageMessageGroupFactory(new ServiceOptions(TranslatablePageMessageGroupFactory::SERVICE_OPTIONS, $services->getMainConfig()),);}, 'Translate:TranslatablePageParser'=> static function(MediaWikiServices $services):TranslatablePageParser { return new TranslatablePageParser($services->get( 'Translate:ParsingPlaceholderFactory'));}, 'Translate:TranslatablePageStateStore'=> static function(MediaWikiServices $services):TranslatablePageStateStore { return new TranslatablePageStateStore($services->get( 'Translate:PersistentCache'), $services->getPageStore());}, 'Translate:TranslatablePageStore'=> static function(MediaWikiServices $services):TranslatablePageStore { return new TranslatablePageStore($services->get( 'Translate:MessageIndex'), $services->getJobQueueGroup(), $services->get( 'Translate:RevTagStore'), $services->getConnectionProvider(), $services->get( 'Translate:TranslatableBundleStatusStore'), $services->get( 'Translate:TranslatablePageParser'), $services->get( 'Translate:MessageGroupMetadata'));}, 'Translate:TranslatablePageView'=> static function(MediaWikiServices $services):TranslatablePageView { return new TranslatablePageView($services->getConnectionProvider(), $services->get( 'Translate:TranslatablePageStateStore'), new ServiceOptions(TranslatablePageView::SERVICE_OPTIONS, $services->getMainConfig()));}, 'Translate:TranslateSandbox'=> static function(MediaWikiServices $services):TranslateSandbox { return new TranslateSandbox($services->getUserFactory(), $services->getConnectionProvider(), $services->getPermissionManager(), $services->getAuthManager(), $services->getUserGroupManager(), $services->getActorStore(), $services->getUserOptionsManager(), $services->getJobQueueGroup(), $services->get( 'Translate:HookRunner'), new ServiceOptions(TranslateSandbox::CONSTRUCTOR_OPTIONS, $services->getMainConfig()));}, 'Translate:TranslationStashReader'=> static function(MediaWikiServices $services):TranslationStashReader { return new TranslationStashStorage( $services->getConnectionProvider() ->getPrimaryDatabase());}, 'Translate:TranslationStatsDataProvider'=> static function(MediaWikiServices $services):TranslationStatsDataProvider { return new TranslationStatsDataProvider(new ServiceOptions(TranslationStatsDataProvider::CONSTRUCTOR_OPTIONS, $services->getMainConfig()), $services->getObjectFactory(), $services->getConnectionProvider());}, 'Translate:TranslationUnitStoreFactory'=> static function(MediaWikiServices $services):TranslationUnitStoreFactory { return new TranslationUnitStoreFactory( $services->getDBLoadBalancer());}, 'Translate:TranslatorActivity'=> static function(MediaWikiServices $services):TranslatorActivity { $query=new TranslatorActivityQuery($services->getMainConfig(), $services->getDBLoadBalancer());return new TranslatorActivity($services->getMainObjectStash(), $query, $services->getJobQueueGroup());}, 'Translate:TtmServerFactory'=> static function(MediaWikiServices $services):TtmServerFactory { $config=$services->getMainConfig();$default=$config->get( 'TranslateTranslationDefaultService');if( $default===false) { $default=null;} return new TtmServerFactory( $config->get( 'TranslateTranslationServices'), $default);}]
@phpcs-require-sorted-array
Class for pointing to messages, like Title class is for titles.
MySQL/MariaDB-based based backend for translation memory.
setDoReIndex()
Instruct the service to fully wipe the index and start from scratch.
expandLocation(array $suggestion)
Given suggestion returned by this TtmServer, constructs fully qualified URL to the location of the tr...
batchInsertDefinitions(array $batch)
Called multiple times per batch if necessary.
update(MessageHandle $handle, ?string $targetText)
Shovels the new translation into translation memory.
endBatch()
Called after every batch (MessageGroup).
query(string $sourceLanguage, string $targetLanguage, string $text)
Fetches all relevant suggestions for given text.
filterForFulltext(string $languageCode, string $input)
Tokenizes the text for fulltext search.
beginBatch()
Called before every batch (MessageGroup).
isLocalSuggestion(array $suggestion)
Determines if the suggestion returned by this TtmServer comes from this wiki or any other wiki.
beginBootstrap()
Called when starting to fill the translation memory.
batchInsertTranslations(array $batch)
Called multiple times per batch if necessary.
Smart string comparator that uses simple string comparison, and then the levenshtein algorithm to com...
Interface for TtmServer that can be queried (=all of them).
Interface for TtmServer that can be updated.