Passed
Push — master ( 9bcfb0...988f4e )
by Alexander
06:53
created

Translator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
/**
4
 * Translator
5
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
Coding Style introduced by
Missing @link tag in file comment
Loading history...
6
namespace Hokan22\LaravelTranslator;
7
8
use Hokan22\LaravelTranslator\Handler\DatabaseHandler;
9
use Hokan22\LaravelTranslator\Handler\HandlerInterface;
10
use Hokan22\LaravelTranslator\Handler\TranslationNotFoundException;
11
use Hokan22\LaravelTranslator\Models\TranslationIdentifier;
12
use Illuminate\Support\Facades\Config;
13
use Illuminate\Support\Facades\Log;
14
use Symfony\Component\Translation\Exception\NotFoundResourceException;
15
16
17
/**
18
 * Class Translator
19
 *
20
 * @category Translator
21
 * @package  Hokan22\LaravelTranslator
22
 * @author   Alexander Viertel <[email protected]>
23
 * @license  http://opensource.org/licenses/MIT MIT
24
 * @link     https://github.com/Hokan22/laravel-translator
25
 */
26
class Translator
27
{
28
    /** @var array|HandlerInterface[] $aHandler Class to Handle the Translation defined in config */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
29
    protected $aHandler = [];
30
    /** @var string $locale The locale to translate to  */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
31
    protected $locale = '';
32
    /** @var string $group The translation group */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
33
    protected $group = 'default';
34
    /** @var string $configName The name of the config file */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
35
    protected $configName = 'translator';
36
    /** @var array $config Config cache */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
37
    protected $config;
38
39
    /**
40
     * Translator constructor.
41
     *
42
     * @param string $locale The locale to translate to
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
43
     * @throws \Exception
0 ignored issues
show
Coding Style introduced by
Tag cannot be grouped with parameter tags in a doc comment
Loading history...
44
     */
45
    public function __construct($locale = '')
46
    {
47
        $this->config = Config::get($this->configName);
48
49
        $this->setLocale($locale);
50
    }
51
52
    /**
53
     * Return the config value for given key
54
     *
55
     * @param string $key Key for the config value to get
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
56
     * @return string|array Config value for $key
0 ignored issues
show
Coding Style introduced by
Tag cannot be grouped with parameter tags in a doc comment
Loading history...
57
     */
58
    public function getConfigValue($key)
59
    {
60
        return $this->config[$key];
61
    }
62
63
    /**
64
     * Actual translate function
65
     * $parameter and $locale are optional
66
     *
67
     * @param string $identifier The identifier of the translation
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
68
     * @param array|null $parameters The parameters to inject into the translation
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
69
     * @param string $locale The locale to which to translate to overrides the class location for one translation
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 5 spaces after parameter name; 1 found
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
70
     * @throws \Exception
0 ignored issues
show
Coding Style introduced by
Tag cannot be grouped with parameter tags in a doc comment
Loading history...
71
     * @return string Returns the translation with replaced parameters
0 ignored issues
show
Coding Style introduced by
Tag cannot be grouped with parameter tags in a doc comment
Loading history...
72
     *
73
     * @todo Make function Parameters interchangeable
74
     */
75
    public function translate($identifier, $parameters = null, $locale = null)
76
    {
77
        // Validate the locale given as parameter or take the saved locale
78
        if ($locale !== null) {
79
            $locale = $this->validateLocale($locale);
80
        } else {
81
            $locale = $this->locale;
82
        }
83
84
        //Create a Handler if no one exists for the current locale
85
        if (!isset($this->aHandler[$locale])) {
86
            $this->aHandler[$locale] = $this->createHandler($locale);
87
        }
88
89
        // Try getting the resulting Translation
90
        // Based on the internal translate function, the getTranslation can throw exceptions
91
        try {
92
            $translation = $this->aHandler[$locale]->getTranslation($identifier, $this->group);
93
94
        } catch (NotFoundResourceException $exception) {
95
            // Thrown when the Identifier wasn't found
96
            // Log exception as error in Laravel log
97
            $this->log($exception, 'error');
98
99
            // Listener: When app is not in production and listening is enabled
100
            // add any missing translation identifier to the database
101
            if ($this->config['listening_enabled'] === true) {
102
                $this->addMissingIdentifier($identifier, $parameters, 'default');
103
            }
104
105
            return $this->returnMissingTranslation($identifier, $locale);
106
107
        } catch (TranslationNotFoundException $exception) {
108
            // Thrown when no translation for the locale was found
109
            // Log exception as error in Laravel log
110
            $this->log($exception, 'error');
111
112
            return $this->returnMissingTranslation($identifier, $locale);
113
        }
114
115
        // If there are no parameters, skip replacement
116
        if (is_array($parameters)) {
117
            $translation = $this->replaceParameter($translation, $parameters);
118
        }
119
120
        if (session('translation_live_mode')) {
121
            $id = $this->aHandler[$locale]->getDatabaseID($identifier);
122
            $translation = $this->addLiveModeLink($translation, $id);
123
        }
124
125
        // Return the translation
126
        return $translation;
127
    }
128
129
    /**
130
     * Inject a Link to the edit page into the translation
131
     *
132
     * @param string $translation
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
133
     * @param integer $id
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
134
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag cannot be grouped with parameter tags in a doc comment
Loading history...
135
     */
136
    public function addLiveModeLink($translation, $id) {
0 ignored issues
show
Coding Style introduced by
Opening brace should be on a new line
Loading history...
137
138
        $route = route('translator.admin.edit', ['id' => $id]);
139
140
        $inject = "<translation-anchor onclick='window.open(\"$route\", \"_blank\")' style='position: absolute; z-index: 999; cursor: pointer;'>&#9875;</translation-anchor>";
141
142
        $translation = "$translation $inject";
143
144
        return $translation;
145
    }
146
147
     /**
0 ignored issues
show
Coding Style introduced by
Doc comment for parameter "$locale" missing
Loading history...
148
      * Sets the Handler
149
      *
150
      * @param $locale
0 ignored issues
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
151
      * @return HandlerInterface
0 ignored issues
show
Coding Style introduced by
Tag cannot be grouped with parameter tags in a doc comment
Loading history...
152
      */
153
    protected function createHandler($locale)
154
    {
155
        // Get the Handler class from config file
156
        $handler_class = $this->config['handler'];
157
158
        // Override Handler Class with Database Handler when in live mode
159
        if (session('translation_live_mode')) {
160
            $handler_class = DatabaseHandler::class;
161
        }
162
163
        $oHandler = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $oHandler is dead and can be removed.
Loading history...
164
165
        // Try to create new Instance of Handler and return it
166
        // If creating the Handler fails or it does not implement HandlerInterface the DatabaseHandler will be used
167
        try {
168
            $oHandler = new $handler_class($locale);
169
            if (!is_a($handler_class, 'Hokan22\LaravelTranslator\Handler\HandlerInterface', true)) {
170
                throw new \Exception($handler_class . ' does not implement HandlerInterface!');
171
            }
172
        } catch (\Exception $exception) {
173
            // Log error and fallback procedure
174
            $this->log($exception, 'error');
175
            $this->log('Falling back to DatabaseHandler', 'warning');
176
177
            // Fallback to Database Handler
178
            $oHandler = new DatabaseHandler($locale);
179
        }
180
        return $oHandler;
181
    }
182
183
    /**
184
     * Set the locale to use in translations
185
     *
186
     * @param string $locale The locale to use
187
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
188
    public function setLocale($locale)
189
    {
190
        $locale = $this->validateLocale($locale);
191
192
        if (!isset($this->aHandler[$locale])) {
193
            $this->aHandler[$locale] = $this->createHandler($locale);
194
        }
195
196
        $this->locale = $locale;
197
    }
198
199
    /**
200
     * Add the missing identifier to the texts table in the database
201
     *
202
     * @param string $identifier The identifier to add to the db
203
     * @param array $parameters The parameters available for the translation
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
204
     * @param string $group The group to put the identifier in
0 ignored issues
show
Coding Style introduced by
Expected 6 spaces after parameter name; 1 found
Loading history...
205
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
206
    public function addMissingIdentifier($identifier, $parameters, $group)
207
    {
208
        if (!$this->hasIdentifier($identifier)) {
209
210
            // Save only the keys from the parameter array
211
            $keys = [];
212
            if (is_array($parameters)) {
0 ignored issues
show
introduced by
The condition is_array($parameters) is always true.
Loading history...
213
                foreach($parameters as $key => $value) {
0 ignored issues
show
Coding Style introduced by
Expected "foreach (...) {\n"; found "foreach(...) {\n"
Loading history...
214
                    $keys[] = $key;
215
                }
216
            }
217
            // Create new TranslationIdentifier with parameters and current url
218
            TranslationIdentifier::create(
219
                [
220
                    "identifier"    => $identifier,
221
                    "parameters"    => $keys,
222
                    "group"         => isset($group) ? $group : 'default',
223
                    "page_name"     => app()->runningInConsole() ? '' : substr(request()->getRequestUri(), 1),
0 ignored issues
show
introduced by
The method runningInConsole() does not exist on Illuminate\Container\Container. Are you sure you never get this type here, but always one of the subclasses? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

223
                    "page_name"     => app()->/** @scrutinizer ignore-call */ runningInConsole() ? '' : substr(request()->getRequestUri(), 1),
Loading history...
224
                ]
225
            );
226
227
            if (isset($this->aHandler[$this->locale])) {
228
                // refresh the Cache for the handler
229
                // When using file Cache, adding the Identifier to the Database will not add it to file Cache!
230
                $this->aHandler[$this->locale]->refreshCache();
231
            }
232
            // Print notice about creation to laravel log
233
            $this->log('The translation string "'.$identifier.'" will be written to the Database', 'notice');
234
        } else {
235
            $this->log('The translation string "'.$identifier.'" is already in the Database!', 'warning');
236
        }
237
    }
238
239
    /**
240
     * Check if the identifier exists in the database
241
     *
242
     * @param string $identifier The identifier to check
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
243
     * @return boolean Returns true if the identifier was found
0 ignored issues
show
Coding Style introduced by
Tag cannot be grouped with parameter tags in a doc comment
Loading history...
244
     */
245
    public function hasIdentifier($identifier)
246
    {
247
        // Returns true if at least one identifier was found
248
        return TranslationIdentifier::where('identifier', $identifier)->count() > 0;
249
    }
250
251
    /**
252
     * Replace the parameters in the translation
253
     *
254
     * @param string $translation The translation with the parameter tags
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
255
     * @param array $parameters The parameters which to inject in the translation
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter name; 1 found
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
256
     * @return string Returns the translation which its parameters replaced
0 ignored issues
show
Coding Style introduced by
Tag cannot be grouped with parameter tags in a doc comment
Loading history...
257
     *
258
     * @todo Make Prefix and Suffix configurable
259
     */
260
    protected function replaceParameter($translation, $parameters)
261
    {
262
        // Go through each specified Parameter and replace its placeholder "{$key}"
263
        foreach ($parameters as $key => $parameter) {
264
            // If the string (e.g "{name}") is not specified within the "parameters" array it won't be replaced!
265
            $translation = str_replace("{".$key."}", $parameter, $translation);
266
        }
267
        return $translation;
268
    }
269
270
    /**
271
     * Return the translation identifier and the locale
272
     *
273
     * @param string $identifier The identifier which is missing
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
274
     * @param string $locale The locale of which the translation is missing
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter name; 1 found
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
275
     * @throws \Exception
0 ignored issues
show
Coding Style introduced by
Tag cannot be grouped with parameter tags in a doc comment
Loading history...
276
     * @return string The string to display instead of the translation
0 ignored issues
show
Coding Style introduced by
Tag cannot be grouped with parameter tags in a doc comment
Loading history...
277
     */
278
    protected function returnMissingTranslation($identifier, $locale)
279
    {
280
        // Return identifier and locale for easier debug
281
        if (config('app.env') !== 'production') {
282
            return '&lt;'.$identifier.':'.$locale.'&gt;';
283
        }
284
        return $identifier;
285
    }
286
287
    /**
288
     * Checks the given locale and returns a valid local
289
     * If no locale was given, first try the locale from the session
290
     * If the Session has no
291
     *
292
     * @param string $locale The locale to validate
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
293
     * @throws NotFoundResourceException
0 ignored issues
show
Coding Style introduced by
Tag cannot be grouped with parameter tags in a doc comment
Loading history...
294
     * @return string Returns the validated Locale
0 ignored issues
show
Coding Style introduced by
Tag cannot be grouped with parameter tags in a doc comment
Loading history...
295
     */
296
    public function validateLocale($locale)
297
    {
298
        // Set message for later log warning
299
        $message = '';
300
301
        //Get Locales configs from translator config file
302
        $avail_locales      = $this->config['available_locales'];
303
        $default_locale     = $this->config['default_locale'];
304
305
        // If locale is already set and not empty it has already been checked
306
        if ($this->locale == $locale && $this->locale !== '') {
307
            return $locale;
308
        }
309
310
        // Fallback if empty locale was given (should be handled in middleware)
311
        if ($locale == null){
0 ignored issues
show
Coding Style introduced by
Expected "if (...) {\n"; found "if (...){\n"
Loading history...
Coding Style introduced by
There must be a single space between the closing parenthesis and the opening brace of a multi-line IF statement; found 0 spaces
Loading history...
312
            if (session()->get('locale') != '') {
313
                $locale = session()->get('locale');
314
            }
315
            else {
0 ignored issues
show
Coding Style introduced by
Expected "} else \n"; found "\n else {\n"
Loading history...
316
                return $default_locale;
317
            }
318
        }
319
320
        // If the given locale is not defined as valid, try to get a fallback locale
321
        if (!in_array($locale, $avail_locales)){
0 ignored issues
show
Coding Style introduced by
Expected "if (...) {\n"; found "if (...){\n"
Loading history...
Coding Style introduced by
There must be a single space between the closing parenthesis and the opening brace of a multi-line IF statement; found 0 spaces
Loading history...
322
323
            $found_locales = [];
324
325
            // Find any available locale which contains the locale as substring
326
            foreach ($avail_locales as $avail_locale) {
327
                if (strpos($avail_locale, $locale) !== false){
0 ignored issues
show
Coding Style introduced by
Expected "if (...) {\n"; found "if (...){\n"
Loading history...
Coding Style introduced by
There must be a single space between the closing parenthesis and the opening brace of a multi-line IF statement; found 0 spaces
Loading history...
328
                    $found_locales[] = $avail_locale;
329
                }
330
            }
331
332
            // Check if default locale is inside the found locales. If it was, use it!
333
            if (in_array($default_locale, $found_locales)){
0 ignored issues
show
Coding Style introduced by
Expected "if (...) {\n"; found "if (...){\n"
Loading history...
Coding Style introduced by
There must be a single space between the closing parenthesis and the opening brace of a multi-line IF statement; found 0 spaces
Loading history...
334
                $message = 'Locale "'.$locale.'" was not found! Falling back to default locale "'.$default_locale.'"';
335
                $locale = $default_locale;
336
337
                // Check if any Locale containing '$locale' was found previously
338
            } elseif (count($found_locales, 0) >= 1) {
339
                $message = 'Locale "'.$locale.'" was not found! Falling back to similar locale "'.$found_locales[0].'"';
340
                $locale = $found_locales[0];
341
            } else {
342
                throw new NotFoundResourceException("Locale '".$locale."' was not found in available locales");
343
            }
344
        }
345
346
        if ($message !== '') $this->log($message, 'warning');
0 ignored issues
show
Coding Style introduced by
Inline control structures are discouraged
Loading history...
347
348
        return $locale;
349
    }
350
351
    /**
352
     * Returns all translation in the in $locale from $group
353
     *
354
     * @param string $locale The locale of the translations to get
0 ignored issues
show
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
355
     * @param string $group The group of the translations to get
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 1 found
Loading history...
Coding Style introduced by
Tag value indented incorrectly; expected 2 spaces but found 1
Loading history...
356
     * @return array|mixed Returns an array of all translation in the $locale from group $group
0 ignored issues
show
Coding Style introduced by
Tag cannot be grouped with parameter tags in a doc comment
Loading history...
357
     */
358
    public function getAllTranslations($locale, $group)
359
    {
360
        if (!isset($this->aHandler[$locale])) {
361
            $this->aHandler[$locale] = $this->createHandler($locale);
362
        }
363
364
        return $this->aHandler[$locale]->getAllTranslations($group);
365
    }
366
367
    /**
368
     * Log the given exception or string $exception as type $log_type when config log_level is set to debug
369
     *
370
     * @param \Exception|string $exception The Exception to log
371
     * @param string $log_type The type of the log to write in the log file
0 ignored issues
show
Coding Style introduced by
Expected 12 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Expected 2 spaces after parameter name; 1 found
Loading history...
372
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
373
    protected function log($exception, $log_type = 'notice')
374
    {
375
        if ($this->config['log_level'] !== 'debug') {
376
            return;
377
        }
378
379
        switch ($log_type) {
380
            case 'error':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
381
                Log::error($exception);
382
                break;
383
384
            case 'warning':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
385
                Log::warning($exception);
386
                break;
387
388
            case 'notice':
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
389
            default :
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
390
                Log::notice($exception);
391
                break;
392
        }
393
    }
394
}