Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
CaighdeanWebService
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 5
182
0.00% covered (danger)
0.00%
0 / 1
 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 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 getQuery
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 parseResponse
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\WebService;
5
6use MediaWiki\Json\FormatJson;
7
8/**
9 * Implements support Caighdean translator api.
10 * @author Niklas Laxström
11 * @license GPL-2.0-or-later
12 * @ingroup TranslationWebService
13 * @since 2017.04
14 * @see https://github.com/kscanne/caighdean/blob/master/API.md
15 */
16class CaighdeanWebService extends TranslationWebService {
17    /** @inheritDoc */
18    public function getType(): string {
19        return 'mt';
20    }
21
22    /** @inheritDoc */
23    protected function mapCode( string $code ): string {
24        return $code;
25    }
26
27    /** @inheritDoc */
28    protected function doPairs(): array {
29        $pairs = [
30            'gd' => [ 'ga' => true ],
31            'gv' => [ 'ga' => true ],
32        ];
33
34        return $pairs;
35    }
36
37    /** @inheritDoc */
38    protected function getQuery( string $text, string $sourceLanguage, string $targetLanguage ): TranslationQuery {
39        if ( !isset( $this->config['url'] ) ) {
40            throw new TranslationWebServiceConfigurationException( '`url` not set in configuration' );
41        }
42
43        $text = trim( $text );
44        if ( $text === '' ) {
45            throw new TranslationWebServiceInvalidInputException( 'Input is empty' );
46        }
47
48        $data = wfArrayToCgi( [
49            'foinse' => $sourceLanguage,
50            'teacs' => $text,
51        ] );
52
53        // Maximum payload is 16 KiB. Based ont testing 16000 bytes is safe by leaving 224
54        // bytes for other things.
55        if ( strlen( $data ) > 16000 ) {
56            throw new TranslationWebServiceInvalidInputException( 'Input is over 16000 bytes long' );
57        }
58
59        return TranslationQuery::factory( $this->config['url'] )
60            ->timeout( intval( $this->config['timeout'] ) )
61            ->postWithData( $data )
62            ->attachProcessingInstructions( $text );
63    }
64
65    /** @inheritDoc */
66    protected function parseResponse( TranslationQueryResponse $reply ): string {
67        $body = $reply->getBody();
68        $response = FormatJson::decode( $body );
69        if ( !is_array( $response ) ) {
70            throw new TranslationWebServiceException( 'Invalid json: ' . serialize( $body ) );
71        }
72
73        $text = '';
74        $originalText = $reply->getQuery()->getProcessingInstructions();
75        foreach ( $response as [ $sourceToken, $targetToken ] ) {
76            $separator = ' ';
77            $pos = strpos( $originalText, $sourceToken );
78            // Try to keep the effects local. If we fail to match at token, we could accidentally
79            // scan very far ahead in the text, find a false match and not find matches for all
80            // of the tokens in the between.
81            if ( $pos !== false && $pos < 50 ) {
82                // Remove the portion of text we have processed. $pos should be zero, unless
83                // we failed to match something earlier.
84                $originalText = substr( $originalText, $pos + strlen( $sourceToken ) );
85                if ( preg_match( '/^\s+/', $originalText, $match ) ) {
86                    $separator = $match[ 0 ];
87                    $originalText = substr( $originalText, strlen( $separator ) );
88                } else {
89                    $separator = '';
90                }
91            }
92
93            $text .= $targetToken . $separator;
94        }
95
96        return $text;
97    }
98}