Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApertiumWebService
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 6
182
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getType
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 mapCode
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 doPairs
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
30
 getQuery
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
6
 parseResponse
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\WebService;
5
6use FormatJson;
7use LanguageCode;
8use MediaWiki\Extension\Translate\Utilities\Utilities;
9use MediaWiki\Http\HttpRequestFactory;
10use Sanitizer;
11
12/**
13 * Implements support Apertium translator API.
14 * @author Niklas Laxström
15 * @license GPL-2.0-or-later
16 * @ingroup TranslationWebService
17 * @since 2013.01
18 * @see https://wiki.apertium.org/wiki/Apertium_web_service
19 */
20class ApertiumWebService extends TranslationWebService {
21    // Exclusions per https://phabricator.wikimedia.org/T177434
22    private const EXCLUDED_TARGET_LANGUAGES = [ 'fr', 'es', 'nl' ];
23    private HttpRequestFactory $httpRequestFactory;
24
25    public function __construct(
26        HttpRequestFactory $httpRequestFactory,
27        string $serviceName,
28        array $config
29    ) {
30        parent::__construct( $serviceName, $config );
31        $this->httpRequestFactory = $httpRequestFactory;
32    }
33
34    /** @inheritDoc */
35    public function getType(): string {
36        return 'mt';
37    }
38
39    /** @inheritDoc */
40    protected function mapCode( string $code ): string {
41        return str_replace( '-', '_', LanguageCode::bcp47( $code ) );
42    }
43
44    /** @inheritDoc */
45    protected function doPairs(): array {
46        $json = $this->httpRequestFactory->get(
47            $this->config['pairs'],
48            [ 'timeout' => $this->config['timeout'] ],
49            __METHOD__
50        );
51        if ( $json === null ) {
52            throw new TranslationWebServiceException( 'Failure encountered when contacting remote server' );
53        }
54
55        $response = FormatJson::decode( $json );
56        if ( !is_object( $response ) ) {
57            throw new TranslationWebServiceException( 'Malformed reply from remote server: ' . $json );
58        }
59
60        $pairs = [];
61        foreach ( $response->responseData as $pair ) {
62            $source = $pair->sourceLanguage;
63            $target = $pair->targetLanguage;
64            if ( !in_array( $target, self::EXCLUDED_TARGET_LANGUAGES ) ) {
65                $pairs[$source][$target] = true;
66            }
67        }
68
69        return $pairs;
70    }
71
72    /** @inheritDoc */
73    protected function getQuery( string $text, string $sourceLanguage, string $targetLanguage ): TranslationQuery {
74        if ( !isset( $this->config['key'] ) ) {
75            throw new TranslationWebServiceConfigurationException( 'API key is not set' );
76        }
77
78        $text = trim( $text );
79        $text = $this->wrapUntranslatable( $text );
80
81        $params = [
82            'q' => $text,
83            'langpair' => "$sourceLanguage|$targetLanguage",
84            'x-application' => 'MediaWiki Translate extension ' . Utilities::getVersion(),
85        ];
86
87        return TranslationQuery::factory( $this->config['url'] )
88            ->timeout( intval( $this->config['timeout'] ) )
89            ->queryParameters( $params );
90    }
91
92    /** @inheritDoc */
93    protected function parseResponse( TranslationQueryResponse $response ): string {
94        $body = $response->getBody();
95        $responseBody = FormatJson::decode( $body );
96        if ( !is_object( $responseBody ) ) {
97            throw new TranslationWebServiceException( 'Invalid json: ' . serialize( $body ) );
98        } elseif ( $responseBody->responseStatus !== 200 ) {
99            throw new TranslationWebServiceException( $responseBody->responseDetails );
100        }
101
102        $text = Sanitizer::decodeCharReferences( $responseBody->responseData->translatedText );
103        $text = $this->unwrapUntranslatable( $text );
104
105        return trim( $text );
106    }
107}