Completed
Push — master ( a0b016...728b96 )
by Stéphane
24:07
created

I18N::getContext()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
nc 5
nop 0
dl 0
loc 22
ccs 0
cts 12
cp 0
crap 30
rs 9.2568
c 0
b 0
f 0
1
<?php namespace Rocket\Translation;
2
3
use Illuminate\Contracts\Cache\Repository as CacheRepository;
4
use Illuminate\Contracts\Config\Repository as ConfigRepository;
5
use Illuminate\Foundation\Application;
6
use Illuminate\Contracts\Session\Session;
7
use Illuminate\Routing\Router;
8
use Illuminate\Http\Request;
9
use Rocket\Translation\Model\Language;
10
use Rocket\Translation\Model\StringModel;
11
use Rocket\Translation\Model\Translation;
12
13
/**
14
 * Class I18N
15
 */
16
class I18N implements I18NInterface
17
{
18
    /**
19
     * An array of the loaded languages
20
     * @var array
21
     */
22
    protected $languagesLoaded = [];
23
24
    /**
25
     * An array of existing languages by ISO
26
     * @var array
27
     */
28
    protected $languagesIso = [];
29
30
    /**
31
     * An array of existing languages by ID
32
     * @var array
33
     */
34
    protected $languagesId = [];
35
36
    /**
37
     * @var integer
38
     */
39
    protected $defaultLanguage;
40
41
    /**
42
     * Language currently in use
43
     * @var string
44
     */
45
    protected $currentLanguage;
46
47
    /**
48
     * Language currently in use (ID)
49
     * @var string
50
     */
51
    protected $currentLanguageId;
52
53
    /**
54
     * All the translation strings
55
     * @var array
56
     */
57
    protected $strings = [];
58
59
    /**
60
     * Context of the current page
61
     * @var string
62
     */
63
    protected $pageContext;
64
65
    /**
66
     * @var CacheRepository The cache to store the terms in
67
     */
68
    protected $cache;
69
70
    /**
71
     * @var Session The session store
72
     */
73
    protected $session;
74
75
    /**
76
     * @var string
77
     */
78
    protected $languageFilesPath;
79
80
    /**
81
     * @var Router
82
     */
83 177
    protected $router;
84
85 177
    /**
86 177
     * Prepare the translation service
87 177
     *
88 177
     * @param Application $app
89
     */
90 177
    public function __construct(Application $app, CacheRepository $cache, Session $session, ConfigRepository $config, Router $router, Request $request)
91 177
    {
92 177
        $this->languageFilesPath = $app->storagePath() . '/languages/';
93 177
        $this->cache = $cache;
94 177
        $this->session = $session;
95
        $this->router = $router;
96 177
97
        $lang = $this->cache->remember(
98 177
            'Lang::List',
99 177
            60 * 24,
100 177
            function () {
101 177
                return Language::all();
102 177
            }
103
        );
104 177
105
        foreach ($lang as $l) {
106 177
            $this->languagesIso[$l->iso] = $this->languagesId[$l->id] = [
107 177
                'id' => $l->id,
108
                'name' => $l->title,
109
                'iso' => $l->iso,
110 177
            ];
111 177
        }
112 177
113
        $this->defaultLanguage = $config['app.locale'];
114
        $fallback = $config['app.fallback_locale'];
115
116
        //current default language
117
        $language = $this->getCurrentLanguage($this->defaultLanguage, $fallback, $session, $request);
118
        $this->setLanguageForRequest($language);
119
    }
120
121
    /**
122
     * Detects the default languages in the following order :
123
     *
124
     * 1. Is a user session var defined ?
125
     * 2. Can we take it from the browser ?
126 177
     * 3. Take the site default
127
     *
128
     * @param $locale string
129 177
     * @param $fallback string
130
     * @throws \RuntimeException if a default language cannot be found
131 177
     * @return string
132
     */
133
    public function getCurrentLanguage($locale, $fallback, Session $session, Request $request)
134
    {
135
        //1. detect user session
136
        $session_lang = $session->get('language');
137 177
        if (!empty($session_lang)) {
138
            return $session_lang;
139
        }
140
141
        //TODO :: move languages to subdomains
142 177
        //Special workaroud : only french for the moment
143
        if (defined('F_LANGUAGES') && !F_LANGUAGES) {
144
            return 'fr';
145 177
        }
146 177
147 177
        //2. detect browser language
148
        $browser_languages = $request->getLanguages();
149 177
        foreach ($browser_languages as $lang) {
150
            if ($this->isAvailable($lang)) {
151 177
                $this->session->put('language', $lang);
152
153
                return $lang;
154
            }
155
        }
156
157
        //3. Site default
158
        if ($this->isAvailable($locale)) {
159
            return $locale;
160
        }
161
162
        //4. Site fallback
163
        if ($this->isAvailable($fallback)) {
164
            return $fallback;
165
        }
166
167
        throw new \RuntimeException('Cannot find an adapted language');
168
    }
169
170
    /**
171
     * Load a language file
172
     *
173
     * @param  string $language
174
     * @return bool
175
     */
176
    public function loadLanguage($language)
177
    {
178
        if ($this->isLoaded($language)) {
179
            return;
180
        }
181
182
        $langfile = $language . '.php';
183
184
        $this->strings[$language] = [];
185
186
        // Determine where the language file is and load it
187
        $filePath = $this->languageFilesPath;
188
        if (file_exists($filePath . $langfile)) {
189
            $this->strings[$language] = include $filePath . $langfile;
190
        }
191 177
192
        $this->languagesLoaded[] = $language;
193 177
    }
194
195
    /**
196
     * Get the current language
197 177
     * @return string
198
     */
199 177
    public function getCurrent()
200
    {
201
        return $this->currentLanguage;
202 177
    }
203
204
    /**
205
     * Get the current language id
206 177
     * @return int
207 177
     */
208
    public function getCurrentId()
209
    {
210
        return $this->currentLanguageId;
211
    }
212
213 27
    /**
214
     * Set the language to use
215 27
     *
216
     * @param  string $language
217
     * @throws \RuntimeException if the language doesn't exist
218
     */
219
    public function setLanguageForRequest($language)
220
    {
221
        if ($language == $this->currentLanguage) {
222 150
            return;
223
        }
224 150
225
        if (!$this->isAvailable($language)) {
226
            throw new \RuntimeException("Language '$language' is not available.");
227
        }
228
229
        if (!$this->isLoaded($language)) {
230
            $this->loadLanguage($language);
231
        }
232
233 177
        switch ($language) {
234
            case 'fr':
235 177
                setlocale(LC_ALL, 'fr_FR.utf8', 'fr_FR.UTF-8', 'fr_FR@euro', 'fr_FR', 'french');
236 156
                break;
237
            case 'en':
238
                setlocale(LC_ALL, 'en_US.utf8', 'en_US.UTF-8', 'en_US');
239 177
                break;
240 177
            case 'de':
241 177
                setlocale(LC_ALL, 'de_DE.utf8', 'de_DE.UTF-8', 'de_DE@euro', 'de_DE', 'deutsch');
242
                break;
243
        }
244 177
245 21
        $this->currentLanguage = $language;
246 21
        $this->currentLanguageId = $this->languagesIso[$language]['id'];
247 177
    }
248 177
249 177
    /**
250
     * Set the current language
251
     *
252
     * @param  string $language
253
     * @throws \RuntimeException if the language doesn't exist
254
     */
255 177
    public function setLanguageForSession($language)
256 177
    {
257 177
        if (!$this->isAvailable($language)) {
258
            throw new \RuntimeException("Language '$language' is not available.");
259
        }
260
261
        $this->session->put('language', $language);
262
263
        $this->setLanguageForRequest($language);
264
    }
265 177
266
    /**
267 177
     * Checks if a language is loaded or not
268
     *
269
     * @param  string $language
270
     * @return bool
271
     */
272
    protected function isLoaded($language)
273
    {
274
        return in_array($language, $this->languagesLoaded);
275
    }
276
277
    /**
278
     * Checks if a language is the default one
279
     *
280
     * @param  string $language
281
     * @return bool
282
     */
283
    protected function isDefault($language)
284
    {
285
        if ($language == 'default' or $this->currentLanguage == $language) {
286
            return true;
287
        }
288
289
        return false;
290
    }
291 177
292
    /**
293 177
     * Checks if the language is availavble
294
     *
295
     * @param  string $language
296
     * @return bool
297
     */
298
    protected function isAvailable($language)
299
    {
300
        return array_key_exists($language, $this->languagesIso);
301
    }
302
303
    /**
304
     * Retrieve languages.
305
     *
306
     * this is a hybrid method.
307
     *
308
     *
309
     *     I18N::languages();
310
     *     returns ['fr' => ['id' => 1, 'name' => 'francais', 'iso' => 'fr'], 'en' => ...]
311
     *
312
     *
313
     *     I18N::languages('fr');
314
     *     returns ['id' => 1, 'name' => 'francais', 'iso' => 'fr']
315
     *
316
     *
317
     *     I18N::languages(1);
318
     *     returns ['id' => 1, 'name' => 'francais', 'iso' => 'fr']
319
     *
320
     *
321 36
     *     I18N::languages('fr', 'id');
322
     *     returns 1
323 36
     *
324 33
     * @param int|string $key
325
     * @param string $subkey
326
     * @return array
327 3
     */
328
    public function languages($key = null, $subkey = null)
329
    {
330
        if ($key === null) {
331
            return $this->languagesIso;
332
        }
333
334
        if (is_int($key)) {
335 3
            if (is_null($subkey)) {
336
                return $this->languagesId[$key];
337
            }
338
339 3
            return $this->languagesId[$key][$subkey];
340
        }
341
342
        if (is_null($subkey)) {
343
            return $this->languagesIso[$key];
344
        }
345
346
        return $this->languagesIso[$key][$subkey];
347
    }
348
349
    public function languagesForSelect()
350
    {
351
        $languages = [];
352
        foreach (static::languages() as $lang) {
353
            $languages[$lang['id']] = t($lang['name'], [], 'languages');
354
        }
355
356
        return $languages;
357
    }
358
359
    /**
360
     * Retreive a string to translate
361
     *
362
     * if it doesn't find it, put it in the database
363
     *
364
     * @param  string $keyString
365
     * @param  string $context
366
     * @param  string $language
367
     * @return string
368
     */
369
    public function translate($keyString, $context = 'default', $language = 'default')
370
    {
371
        
372
        if ($this->isDefault($language)) {
373
            $language = $this->getCurrent();
374
            $languageId = $this->getCurrentId();
375
        } else {
376
            if (!$this->isAvailable($language)) {
377
                throw new \RuntimeException("Language '$language' is not available");
378
            }
379
            $this->loadLanguage($language);
380
            $languageId = $this->languagesIso[$language]['id'];
381
        }
382
383
        // Read string from cache
384
        if (array_key_exists($context, $this->strings[$language]) &&
385
            array_key_exists($keyString, $this->strings[$language][$context])) {
386
            return $this->strings[$language][$context][$keyString];
387
        }
388
389
        // Read string from database
390
        $text = StringModel::getOrCreateTranslation($context, $keyString, $languageId, $this->languages($this->defaultLanguage, 'id'));
391
        if ($text) {
392
            // Store in cache for this request
393
            $this->strings[$language][$context][$keyString] = $text;
394
395
            return $text;
396
        }
397
398
        return $keyString;
399
    }
400
401
    /**
402
     * Get the page's context
403
     *
404
     * @return string
405
     */
406
    public function getContext()
407
    {
408
        if ($this->pageContext) {
409
            return $this->pageContext;
410
        }
411
412
        $current = $this->router->current();
413
414
        if (!$current) {
415
            return 'default';
416
        }
417
418
        if ($current->getName()) {
419
            return $this->pageContext = $current->getName();
420
        }
421
422
        if ($current->getActionName() != "Closure") {
423
            return $this->pageContext = $current->getActionName();
424
        }
425
426
        return $this->pageContext = trim($current->uri(), "/");
427
    }
428
429
    public function dumpCache()
430
    {
431
        $filePath = $this->languageFilesPath;
432
433
        if (!is_dir($filePath)) {
434
            mkdir($filePath, 0755, true);
435
            chmod($filePath, 0755);
436
        }
437
438
        foreach ($this->languages() as $lang => $d) {
439
            $strings = StringModel::select('string', 'text', 'context')
440
                ->where('language_id', $d['id'])
441
                ->join((new Translation)->getTable(), 'strings.id', '=', 'string_id', 'left')
442
                ->get();
443
444
            $final_strings = [];
445
            foreach ($strings as $s) {
446
                $final_strings[$s->context][$s->string] = $s->text;
447
            }
448
449
            file_put_contents("{$filePath}{$lang}.php", '<?php return ' . var_export($final_strings, true) . ';');
450
        }
451
    }
452
}
453