Translation::getTranslationModel()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace JosephNC\Translation;
4
5
use Illuminate\Contracts\Foundation\Application;
6
use Illuminate\Support\Facades\Log;
7
use Carbon\Carbon;
8
use Exception;
9
use InvalidArgumentException;
10
use UnexpectedValueException;
11
use GoogleTranslate\Client as T1;
12
use Stichoza\GoogleTranslate\GoogleTranslate as T2;
13
14
class Translation
15
{
16
    /**
17
     * Holds the app configuration.
18
     * 
19
     * @access protected
20
     * @var Illuminate\Config\Repository
0 ignored issues
show
Bug introduced by
The type JosephNC\Translation\Illuminate\Config\Repository was not found. Did you mean Illuminate\Config\Repository? If so, make sure to prefix the type with \.
Loading history...
21
     */
22
    public $config;
23
24
    /**
25
     * Holds the current request.
26
     * 
27
     * @access protected
28
     * @var Illuminate\Http\Request
0 ignored issues
show
Bug introduced by
The type JosephNC\Translation\Illuminate\Http\Request was not found. Did you mean Illuminate\Http\Request? If so, make sure to prefix the type with \.
Loading history...
29
     */
30
    protected $request;
31
32
    /**
33
     * Represents the translation model
34
     * 
35
     * @access protected
36
     * @var JosephNC\Translation\Models\Translation
0 ignored issues
show
Bug introduced by
The type JosephNC\Translation\Jos...tion\Models\Translation was not found. Did you mean JosephNC\Translation\Models\Translation? If so, make sure to prefix the type with \.
Loading history...
37
     */
38
    protected $translationModel;
39
40
    /**
41
     * Translation constructor
42
     * 
43
     * @access public
44
     * @var Illuminate\Contracts\Foundation\Application
45
     */
46
    public function __construct( Application $app )
47
    {
48
        $this->config           = $app->make('config');
0 ignored issues
show
Documentation Bug introduced by
It seems like $app->make('config') of type Illuminate\Config\Repository is incompatible with the declared type JosephNC\Translation\Illuminate\Config\Repository of property $config.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
49
        $this->request          = app( \Illuminate\Http\Request::class );
0 ignored issues
show
Documentation Bug introduced by
It seems like app(Illuminate\Http\Request::class) of type Illuminate\Http\Request is incompatible with the declared type JosephNC\Translation\Illuminate\Http\Request of property $request.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
50
        $this->translationModel = $app->make($this->getTranslationModel());
51
    }
52
53
    /**
54
     * Returns the API Key
55
     * 
56
     * @return string
57
     */
58
    public function getApiKey() : string
59
    {
60
        return (string) $this->config->get( 'translation.key', '' );
61
    }
62
63
    /**
64
     * Returns the locale
65
     * 
66
     * @return string
67
     */
68
    public function getLocale() : string
69
    {
70
        $locale = $_SESSION['locale'] ?? $this->getDefaultLocale();
71
72
        return (string) ( empty( $locale ) ? $this->getDefaultLocale() : $locale );
73
    }
74
75
    /**
76
     * Returns the array of configuration locales.
77
     *
78
     * @return array
79
     */
80
    protected function getLocales() : array
81
    {
82
        return (array) $this->config->get( 'translation.locales' );
83
    }
84
85
    /**
86
     * Returns the default locale from the configuration.
87
     *
88
     * @access protected
89
     * 
90
     * @return string
91
     */
92
    protected function getDefaultLocale() : string
93
    {
94
        $locale = $this->config->get( 'app.locale', $this->config->get('app.fallback_locale') );
95
96
        $locale = $this->localeExist( $locale ) ? $locale : 'en';
97
98
        return (string) $locale;
99
    }
100
101
    /**
102
     * Returns the translation model from the configuration.
103
     *
104
     * @access protected
105
     * 
106
     * @return string
107
     */
108
    protected function getTranslationModel() : string
109
    {
110
        return (string) $this->config->get('translation.models.translation', Models\Translation::class);
111
    }
112
113
    /**
114
     * Returns the current route translation prefix
115
     * using the srequest segment set in the config
116
     * 
117
     * @return string
118
     */
119
    public function getRoutePrefix() : string
120
    {
121
        $locale = (string) $this->request->segment( $this->getRequestSegment() );
122
123
        return $this->localeExist( $locale ) ? $locale : '';
124
    }
125
126
    /**
127
     * Returns the request segment to retrieve the locale from.
128
     *
129
     * @return int
130
     */
131
    protected function getRequestSegment() : int
132
    {
133
        return $this->config->get( 'translation.request_segment', 1 );
134
    }
135
136
    /**
137
     * Sets the locale
138
     * 
139
     * @param string $locale    The locale to use. Defaults to 'en'.
140
     * @throws InvalidArgumentException|Exception
141
     */
142
    public function setLocale( string $locale = 'en' )
143
    {
144
        if ( ! empty( $locale ) && ! $this->localeExist( $locale ) ) {
145
            $message = 'Invalid Argument! Locale passed does not exist.';
146
147
            throw new InvalidArgumentException( $message );
148
        }
149
150
        $_SESSION['locale'] = $locale;
151
    }
152
153
    /**
154
     * Checks if the locale passed is exist
155
     *
156
     * @param string $locale    The locale to check
157
     * 
158
     * @return bool
159
     */
160
    public function localeExist( string $locale = 'en' ) : bool
161
    {
162
        return array_key_exists( $locale, (array) $this->getLocales() ) ? true : false;
163
    }
164
165
    /**
166
     * Translate the text
167
     * 
168
     * @access public
169
     * 
170
     * @param string $text
171
     * @param array $replacements
172
     * @param string $to_locale
173
     * 
174
     * @throws  InvalidArgumentException
175
     * 
176
     * @return string   The translated text.
177
     */
178
    public function translate( string $text, array $replacements = [], string $to_locale = '' ) : string
179
    {
180
        $do_translate   = false;
181
        $data           = [];
182
        $locale         = 'en';
183
        $to_locale      = empty( $to_locale ) ? $this->getLocale() : $to_locale;
184
        $text           = preg_replace( '/:([a-z]+)/i', '__$1__', $text ); // Turn replacements to placeholders
185
        $trans          = $text;
186
        $translations   = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $translations is dead and can be removed.
Loading history...
187
188
        if ( ! array_key_exists( $to_locale, $this->getLocales() ) ) {
189
            $message = 'Invalid Argument. Locale not found for translation.';
190
191
            throw new InvalidArgumentException( $message );
192
        }
193
194
        if ( empty( $text ) ) return $text;
195
196
        // Get translation data from session or database
197
        $translations = (array) ($_SESSION['__translations'] ?? $this->translationModel->pluck( 'data', 'text' )->toArray());
198
199
        if ( ( empty( $translations ) || ! isset( $translations[ $text ] ) ) && $locale != $to_locale ) {
200
            $do_translate = true;
201
        } else if ( isset( $translations[ $text ] ) ) {
202
            $data = json_decode( $translations[ $text ], true );
203
204
            if ( $locale != $to_locale ) {
205
                $trans = $data[ $to_locale ] ?? '';
206
207
                $do_translate = ! empty( $trans ) && $trans == $text ? true : ( empty( $trans ) ? true : false );
208
            }
209
        }
210
211
        if ( $do_translate ) {
212
            // Let's request for translation
213
            try {
214
                $trans = (new T1( $this->getApiKey() ) )->translate( $text, $to_locale, $locale );
215
216
            } catch (\Exception $e) {
217
                Log::info( $e->getMessage() );
218
219
                $trans = T2::trans( $text, $to_locale, $locale );
220
            }
221
        }
222
223
        $data = array_merge( $data, [ $to_locale => $trans ] );
224
        $translations[ $text ] = json_encode( $data );
225
226
        // Save to session
227
        $_SESSION['__translations'] = $translations;
228
229
        return (string) ( empty( $replacements ) ? $trans : $this->makeReplacements( $trans, $replacements ) );
230
    }
231
232
    /**
233
     * Replaces placeholders with its real value
234
     * 
235
     * @access private
236
     * @param string $text  The text having the placeholder
237
     * @param array $replacements   The replacement values in array
238
     * 
239
     * @return string   The replaced text
240
     */
241
    private function makeReplacements( string $text, array $replacements ) : string
242
    {
243
        $keys       = strtolower( '__' . join( '__,__', array_keys( $replacements ) ) . '__' );
244
        $search     = explode( ',', $keys );
245
        $replace    = array_values( $replacements );
246
247
        return (string) str_replace( $search, $replace, $text );
248
    }
249
250
    /**
251
     * Runs on page shutdown
252
     * 
253
     * @access public
254
     */
255
    public function shutdown()
256
    {
257
        // Get translation data from session
258
        $new_translations = $_SESSION['__translations'] ?? [];
259
        $old_translations = (array) $this->translationModel->pluck( 'data', 'text' )->toArray();
260
261
        if ( json_encode( $new_translations ) == json_encode( $old_translations ) ) return;
262
263
        $now = Carbon::now('utc')->toDateTimeString();
264
        $insert = $update = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $update is dead and can be removed.
Loading history...
265
266
        if ( empty( $new_translations ) ) return;
267
268
        foreach ($new_translations as $text => $data) {
269
            if ( isset( $old_translations[ $text ] ) ) {
270
                if ( $old_translations[ $text ] == $data ) continue;
271
272
                // Update old
273
                $this->translationModel->where( 'text', $text )->update( [ 'data' => $data ] );
274
                continue;
275
            }
276
277
            // Create new
278
            $insert[] = [
279
                'text'          => $text,
280
                'data'          => $data,
281
                'created_at'    => $now,
282
                'updated_at'    => $now
283
            ];
284
        }
285
286
        if ( ! empty( $insert ) ) $this->translationModel->insert( $insert );
287
288
        // Remove the translation
289
        if ( isset( $_SESSION['__translations'] ) ) unset( $_SESSION['__translations'] );
290
    }
291
}
292