Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
TTMServerAid.php
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\TranslatorInterface\Aid;
5
6use Exception;
7use IContextSource;
16use MessageGroup;
18use Title;
19use TTMServer;
20
30 private $services;
32 private $ttmServerFactory;
33
34 public function __construct(
35 MessageGroup $group,
36 MessageHandle $handle,
37 IContextSource $context,
38 TranslationAidDataProvider $dataProvider
39 ) {
40 parent::__construct( $group, $handle, $context, $dataProvider );
41 $this->ttmServerFactory = Services::getInstance()->getTtmServerFactory();
42 }
43
44 public function populateQueries(): void {
45 $text = $this->dataProvider->getDefinition();
46 $from = $this->group->getSourceLanguage();
47 $to = $this->handle->getCode();
48
49 if ( trim( $text ) === '' ) {
50 return;
51 }
52
53 foreach ( $this->getWebServices() as $service ) {
54 $this->storeQuery( $service, $from, $to, $text );
55 }
56 }
57
58 public function getData(): array {
59 $text = $this->dataProvider->getDefinition();
60 if ( trim( $text ) === '' ) {
61 return [];
62 }
63
64 $suggestions = [];
65 $from = $this->group->getSourceLanguage();
66 $to = $this->handle->getCode();
67
68 foreach ( $this->getInternalServices() as $name => $service ) {
69 try {
70 $queryData = $service->query( $from, $to, $text );
71 } catch ( TranslationHelperException $e ) {
72 throw $e;
73 } catch ( Exception $e ) {
74 // Not ideal to catch all exceptions
75 continue;
76 }
77
78 $sugs = $this->formatInternalSuggestions( $queryData, $service, $name, $from );
79 $suggestions = array_merge( $suggestions, $sugs );
80 }
81
82 // Results from web services
83 foreach ( $this->getQueryData() as $queryData ) {
84 $sugs = $this->formatWebSuggestions( $queryData );
85 $suggestions = array_merge( $suggestions, $sugs );
86 }
87
88 $suggestions = TTMServer::sortSuggestions( $suggestions );
89 // Must be here to not mess up the sorting function
90 $suggestions['**'] = 'suggestion';
91
92 return $suggestions;
93 }
94
95 protected function formatWebSuggestions( array $queryData ): array {
96 $service = $queryData['service'];
97 $response = $queryData['response'];
98 $sourceLanguage = $queryData['language'];
99 $sourceText = $queryData['text'];
100
101 // getResultData returns a null on failure instead of throwing an exception
102 $items = $service->getResultData( $response );
103 if ( $items === null ) {
104 return [];
105 }
106
107 $localPrefix = Title::makeTitle( NS_MAIN, '' )->getFullURL( '', false, PROTO_CANONICAL );
108 $localPrefixLength = strlen( $localPrefix );
109
110 foreach ( $items as &$item ) {
111 $local = strncmp( $item['uri'], $localPrefix, $localPrefixLength ) === 0;
112 $item = array_merge( $item, [
113 'service' => $service->getName(),
114 'source_language' => $sourceLanguage,
115 'source' => $sourceText,
116 'local' => $local,
117 ] );
118
119 // TtmServerActionApi expands this... need to fix it again to be the bare name
120 if ( $local ) {
121 $pagename = urldecode( substr( $item['location'], $localPrefixLength ) );
122 $item['location'] = $pagename;
123 $handle = new MessageHandle( Title::newFromText( $pagename ) );
124 $item['editorUrl'] = Utilities::getEditorUrl( $handle );
125 }
126 }
127 return $items;
128 }
129
130 protected function formatInternalSuggestions(
131 array $queryData,
132 ReadableTtmServer $s,
133 string $serviceName,
134 string $sourceLanguage
135 ): array {
136 $items = [];
137
138 foreach ( $queryData as $item ) {
139 $local = $s->isLocalSuggestion( $item );
140
141 $item['service'] = $serviceName;
142 $item['source_language'] = $sourceLanguage;
143 $item['local'] = $local;
144 // Likely only needed for non-public DatabaseTtmServer
145 $item['uri'] = $item['uri'] ?? $s->expandLocation( $item );
146 if ( $local ) {
147 $handle = new MessageHandle( Title::newFromText( $item[ 'location' ] ) );
148 $item['editorUrl'] = Utilities::getEditorUrl( $handle );
149 }
150 $items[] = $item;
151 }
152
153 return $items;
154 }
155
157 private function getInternalServices(): array {
158 $services = $this->getQueryableServices();
159 foreach ( $services as $name => $config ) {
160 if ( $config['type'] === 'ttmserver' ) {
161 $services[$name] = $this->ttmServerFactory->create( $name );
162 } else {
163 unset( $services[$name] );
164 }
165 }
166
167 return $services;
168 }
169
171 private function getWebServices(): array {
172 $services = $this->getQueryableServices();
173 foreach ( $services as $name => $config ) {
174 if ( $config['type'] === 'remote-ttmserver' ) {
175 $services[$name] = TranslationWebService::factory( $name, $config );
176 } else {
177 unset( $services[$name] );
178 }
179 }
180
181 return $services;
182 }
183
184 private function getQueryableServices(): array {
185 if ( !$this->services ) {
186 global $wgTranslateTranslationServices;
187 $this->services = $this->getQueryableServicesUncached(
188 $wgTranslateTranslationServices );
189 }
190
191 return $this->services;
192 }
193
194 private function getQueryableServicesUncached( array $services ): array {
195 // First remove mirrors of the default service
196 $primary = $this->ttmServerFactory->getDefaultForQuerying();
197 if ( $primary instanceof WritableTtmServer ) {
198 $mirrors = $primary->getMirrors();
199 foreach ( $mirrors as $mirrorName ) {
200 unset( $services[$mirrorName] );
201 }
202 }
203
204 // Remove writable services
205 $writableServices = $this->ttmServerFactory->getWriteOnly();
206 foreach ( array_keys( $writableServices ) as $serviceId ) {
207 unset( $services[ $serviceId ] );
208 }
209
210 // Then remove non-ttmservers
211 foreach ( $services as $name => $config ) {
212 $type = $config['type'];
213 if ( $type !== 'ttmserver' && $type !== 'remote-ttmserver' ) {
214 unset( $services[$name] );
215 }
216 }
217
218 // Then determine the query method. Prefer HTTP queries that can be run parallel.
219 foreach ( $services as $name => &$config ) {
220 $public = $config['public'] ?? false;
221 if ( $config['type'] === 'ttmserver' && $public ) {
222 $config['type'] = 'remote-ttmserver';
223 $config['service'] = $name;
224 $config['url'] = wfExpandUrl( wfScript( 'api' ), PROTO_CANONICAL );
225 }
226 }
227
228 return $services;
229 }
230}
Minimal service container.
Definition Services.php:44
storeQuery(TranslationWebService $service, string $from, string $to, string $text)
Stores a web service query for later execution.
Translation aid that provides suggestion from translation memory.
getData()
Translation aid class should implement this function.
Translation helpers can throw this exception when they cannot do anything useful with the current mes...
Essentially random collection of helper functions, similar to GlobalFunctions.php.
Definition Utilities.php:31
Class for pointing to messages, like Title class is for titles.
Some general static methods for instantiating TTMServer and helpers.
Definition TTMServer.php:19
static sortSuggestions(array $suggestions)
Definition TTMServer.php:32
Interface for TTMServer that can be queried (=all of them).
Interface for TTMServer that can be updated.
Interface for message groups.