1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Mcamara\LaravelLocalization; |
4
|
|
|
|
5
|
|
|
use Illuminate\Config\Repository; |
6
|
|
|
use Illuminate\Contracts\Routing\UrlRoutable; |
7
|
|
|
use Mcamara\LaravelLocalization\Exceptions\SupportedLocalesNotDefined; |
8
|
|
|
use Mcamara\LaravelLocalization\Exceptions\UnsupportedLocaleException; |
9
|
|
|
|
10
|
|
|
class LaravelLocalization |
11
|
|
|
{ |
12
|
|
|
/** |
13
|
|
|
* The env key that the forced locale for routing is stored in. |
14
|
|
|
*/ |
15
|
|
|
const ENV_ROUTE_KEY = 'ROUTING_LOCALE'; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Config repository. |
19
|
|
|
* |
20
|
|
|
* @var \Illuminate\Config\Repository |
21
|
|
|
*/ |
22
|
|
|
protected $configRepository; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* Illuminate view Factory. |
26
|
|
|
* |
27
|
|
|
* @var \Illuminate\View\Factory |
28
|
|
|
*/ |
29
|
|
|
protected $view; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Illuminate translator class. |
33
|
|
|
* |
34
|
|
|
* @var \Illuminate\Translation\Translator |
35
|
|
|
*/ |
36
|
|
|
protected $translator; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Illuminate router class. |
40
|
|
|
* |
41
|
|
|
* @var \Illuminate\Routing\Router |
42
|
|
|
*/ |
43
|
|
|
protected $router; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* Illuminate request class. |
47
|
|
|
* |
48
|
|
|
* @var \Illuminate\Routing\Request |
49
|
|
|
*/ |
50
|
|
|
protected $request; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Illuminate url class. |
54
|
|
|
* |
55
|
|
|
* @var \Illuminate\Routing\UrlGenerator |
56
|
|
|
*/ |
57
|
|
|
protected $url; |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Illuminate request class. |
61
|
|
|
* |
62
|
|
|
* @var Illuminate\Foundation\Application |
63
|
|
|
*/ |
64
|
|
|
protected $app; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* Illuminate request class. |
68
|
|
|
* |
69
|
|
|
* @var string |
70
|
|
|
*/ |
71
|
|
|
protected $baseUrl; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* Default locale. |
75
|
|
|
* |
76
|
|
|
* @var string |
77
|
|
|
*/ |
78
|
|
|
protected $defaultLocale; |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* Supported Locales. |
82
|
|
|
* |
83
|
|
|
* @var array |
84
|
|
|
*/ |
85
|
|
|
protected $supportedLocales; |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* Current locale. |
89
|
|
|
* |
90
|
|
|
* @var string |
91
|
|
|
*/ |
92
|
|
|
protected $currentLocale = false; |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* An array that contains all routes that should be translated. |
96
|
|
|
* |
97
|
|
|
* @var array |
98
|
|
|
*/ |
99
|
|
|
protected $translatedRoutes = []; |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* Name of the translation key of the current route, it is used for url translations. |
103
|
|
|
* |
104
|
|
|
* @var string |
105
|
|
|
*/ |
106
|
|
|
protected $routeName; |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* An array that contains all translated routes by url |
110
|
|
|
* |
111
|
|
|
* @var array |
112
|
|
|
*/ |
113
|
|
|
protected $cachedTranslatedRoutesByUrl = []; |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* Creates new instance. |
117
|
|
|
* |
118
|
|
|
* @throws UnsupportedLocaleException |
119
|
|
|
*/ |
120
|
|
|
public function __construct() |
121
|
|
|
{ |
122
|
|
|
$this->app = app(); |
123
|
|
|
|
124
|
|
|
$this->configRepository = $this->app['config']; |
125
|
|
|
$this->view = $this->app['view']; |
126
|
|
|
$this->translator = $this->app['translator']; |
127
|
|
|
$this->router = $this->app['router']; |
128
|
|
|
$this->request = $this->app['request']; |
129
|
|
|
$this->url = $this->app['url']; |
130
|
|
|
|
131
|
|
|
// set default locale |
132
|
|
|
$this->defaultLocale = $this->configRepository->get('app.locale'); |
133
|
|
|
$supportedLocales = $this->getSupportedLocales(); |
134
|
|
|
|
135
|
|
|
if (empty($supportedLocales[$this->defaultLocale])) { |
136
|
|
|
throw new UnsupportedLocaleException('Laravel default locale is not in the supportedLocales array.'); |
137
|
|
|
} |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* Set and return current locale. |
142
|
|
|
* |
143
|
|
|
* @param string $locale Locale to set the App to (optional) |
144
|
|
|
* |
145
|
|
|
* @return string Returns locale (if route has any) or null (if route does not have a locale) |
146
|
|
|
*/ |
147
|
|
|
public function setLocale($locale = null) |
148
|
|
|
{ |
149
|
|
|
if (empty($locale) || !\is_string($locale)) { |
150
|
|
|
// If the locale has not been passed through the function |
151
|
|
|
// it tries to get it from the first segment of the url |
152
|
|
|
$locale = $this->request->segment(1); |
153
|
|
|
|
154
|
|
|
// If the locale is determined by env, use that |
155
|
|
|
// Note that this is how per-locale route caching is performed. |
156
|
|
|
if ( ! $locale) { |
157
|
|
|
$locale = $this->getForcedLocale(); |
158
|
|
|
} |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
if (!empty($this->supportedLocales[$locale])) { |
162
|
|
|
$this->currentLocale = $locale; |
163
|
|
|
} else { |
164
|
|
|
// if the first segment/locale passed is not valid |
165
|
|
|
// the system would ask which locale have to take |
166
|
|
|
// it could be taken by the browser |
167
|
|
|
// depending on your configuration |
168
|
|
|
|
169
|
|
|
$locale = null; |
170
|
|
|
|
171
|
|
|
// if we reached this point and hideDefaultLocaleInURL is true |
172
|
|
|
// we have to assume we are routing to a defaultLocale route. |
173
|
|
|
if ($this->hideDefaultLocaleInURL()) { |
174
|
|
|
$this->currentLocale = $this->defaultLocale; |
175
|
|
|
} |
176
|
|
|
// but if hideDefaultLocaleInURL is false, we have |
177
|
|
|
// to retrieve it from the browser... |
178
|
|
|
else { |
179
|
|
|
$this->currentLocale = $this->getCurrentLocale(); |
180
|
|
|
} |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
$this->app->setLocale($this->currentLocale); |
184
|
|
|
|
185
|
|
|
// Regional locale such as de_DE, so formatLocalized works in Carbon |
186
|
|
|
$regional = $this->getCurrentLocaleRegional(); |
187
|
|
|
$suffix = $this->configRepository->get('laravellocalization.utf8suffix'); |
188
|
|
|
if ($regional) { |
189
|
|
|
setlocale(LC_TIME, $regional . $suffix); |
190
|
|
|
setlocale(LC_MONETARY, $regional . $suffix); |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
return $locale; |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
/** |
197
|
|
|
* Check if $locale is default locale and supposed to be hidden in url |
198
|
|
|
* |
199
|
|
|
* @param string $locale Locale to be checked |
200
|
|
|
* |
201
|
|
|
* @return boolean Returns true if above requirement are met, otherwise false |
202
|
|
|
*/ |
203
|
|
|
|
204
|
|
|
public function isHiddenDefault($locale) |
205
|
|
|
{ |
206
|
|
|
return ($this->getDefaultLocale() === $locale && $this->hideDefaultLocaleInURL()); |
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* Set and return supported locales. |
211
|
|
|
* |
212
|
|
|
* @param array $locales Locales that the App supports |
213
|
|
|
*/ |
214
|
|
|
public function setSupportedLocales($locales) |
215
|
|
|
{ |
216
|
|
|
$this->supportedLocales = $locales; |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
/** |
220
|
|
|
* Returns an URL adapted to $locale or current locale. |
221
|
|
|
* |
222
|
|
|
* @param string $url URL to adapt. If not passed, the current url would be taken. |
223
|
|
|
* @param string|bool $locale Locale to adapt, false to remove locale |
224
|
|
|
* |
225
|
|
|
* @throws UnsupportedLocaleException |
226
|
|
|
* |
227
|
|
|
* @return string URL translated |
228
|
|
|
*/ |
229
|
|
|
public function localizeURL($url = null, $locale = null) |
230
|
|
|
{ |
231
|
|
|
return $this->getLocalizedURL($locale, $url); |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* Returns an URL adapted to $locale. |
236
|
|
|
* |
237
|
|
|
* |
238
|
|
|
* @param string|bool $locale Locale to adapt, false to remove locale |
239
|
|
|
* @param string|false $url URL to adapt in the current language. If not passed, the current url would be taken. |
240
|
|
|
* @param array $attributes Attributes to add to the route, if empty, the system would try to extract them from the url. |
241
|
|
|
* @param bool $forceDefaultLocation Force to show default location even hideDefaultLocaleInURL set as TRUE |
242
|
|
|
* |
243
|
|
|
* @throws SupportedLocalesNotDefined |
244
|
|
|
* @throws UnsupportedLocaleException |
245
|
|
|
* |
246
|
|
|
* @return string|false URL translated, False if url does not exist |
247
|
|
|
*/ |
248
|
|
|
public function getLocalizedURL($locale = null, $url = null, $attributes = [], $forceDefaultLocation = false) |
249
|
|
|
{ |
250
|
|
|
if ($locale === null) { |
251
|
|
|
$locale = $this->getCurrentLocale(); |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
if (!$this->checkLocaleInSupportedLocales($locale)) { |
255
|
|
|
throw new UnsupportedLocaleException('Locale \''.$locale.'\' is not in the list of supported locales.'); |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
if (empty($attributes)) { |
259
|
|
|
$attributes = $this->extractAttributes($url, $locale); |
|
|
|
|
260
|
|
|
} |
261
|
|
|
$urlQuery = parse_url($url, PHP_URL_QUERY); |
262
|
|
|
$urlQuery = $urlQuery ? '?'.$urlQuery : ''; |
263
|
|
|
|
264
|
|
|
if (empty($url)) { |
265
|
|
|
if (!empty($this->routeName)) { |
266
|
|
|
return $this->getURLFromRouteNameTranslated($locale, $this->routeName, $attributes, $forceDefaultLocation); |
267
|
|
|
} |
268
|
|
|
|
269
|
|
|
$url = $this->request->fullUrl(); |
270
|
|
|
} else { |
271
|
|
|
$url = $this->url->to($url); |
272
|
|
|
$url = preg_replace('/'. preg_quote($urlQuery, '/') . '$/', '', $url); |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
if ($locale && $translatedRoute = $this->findTranslatedRouteByUrl($url, $attributes, $this->currentLocale)) { |
276
|
|
|
return $this->getURLFromRouteNameTranslated($locale, $translatedRoute, $attributes, $forceDefaultLocation).$urlQuery; |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
$base_path = $this->request->getBaseUrl(); |
280
|
|
|
$parsed_url = parse_url($url); |
281
|
|
|
$url_locale = $this->getDefaultLocale(); |
282
|
|
|
|
283
|
|
|
if (!$parsed_url || empty($parsed_url['path'])) { |
284
|
|
|
$path = $parsed_url['path'] = ''; |
285
|
|
|
} else { |
286
|
|
|
$parsed_url['path'] = str_replace($base_path, '', '/'.ltrim($parsed_url['path'], '/')); |
287
|
|
|
$path = $parsed_url['path']; |
288
|
|
|
foreach ($this->getSupportedLocales() as $localeCode => $lang) { |
289
|
|
|
$parsed_url['path'] = preg_replace('%^/?'.$localeCode.'/%', '$1', $parsed_url['path']); |
290
|
|
|
if ($parsed_url['path'] !== $path) { |
291
|
|
|
$url_locale = $localeCode; |
292
|
|
|
break; |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
$parsed_url['path'] = preg_replace('%^/?'.$localeCode.'$%', '$1', $parsed_url['path']); |
296
|
|
|
if ($parsed_url['path'] !== $path) { |
297
|
|
|
$url_locale = $localeCode; |
298
|
|
|
break; |
299
|
|
|
} |
300
|
|
|
} |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
$parsed_url['path'] = ltrim($parsed_url['path'], '/'); |
304
|
|
|
|
305
|
|
|
if ($translatedRoute = $this->findTranslatedRouteByPath($parsed_url['path'], $url_locale)) { |
306
|
|
|
return $this->getURLFromRouteNameTranslated($locale, $translatedRoute, $attributes, $forceDefaultLocation).$urlQuery; |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
if (!empty($locale)) { |
310
|
|
|
if ($forceDefaultLocation || $locale != $this->getDefaultLocale() || !$this->hideDefaultLocaleInURL()) { |
311
|
|
|
$parsed_url['path'] = $locale.'/'.ltrim($parsed_url['path'], '/'); |
312
|
|
|
} |
313
|
|
|
} |
314
|
|
|
$parsed_url['path'] = ltrim(ltrim($base_path, '/').'/'.$parsed_url['path'], '/'); |
315
|
|
|
|
316
|
|
|
//Make sure that the pass path is returned with a leading slash only if it come in with one. |
317
|
|
|
if (starts_with($path, '/') === true) { |
|
|
|
|
318
|
|
|
$parsed_url['path'] = '/'.$parsed_url['path']; |
319
|
|
|
} |
320
|
|
|
$parsed_url['path'] = rtrim($parsed_url['path'], '/'); |
321
|
|
|
|
322
|
|
|
$url = $this->unparseUrl($parsed_url); |
323
|
|
|
|
324
|
|
|
if ($this->checkUrl($url)) { |
325
|
|
|
return $url.$urlQuery; |
326
|
|
|
} |
327
|
|
|
|
328
|
|
|
return $this->createUrlFromUri($url).$urlQuery; |
329
|
|
|
} |
330
|
|
|
|
331
|
|
|
/** |
332
|
|
|
* Returns an URL adapted to the route name and the locale given. |
333
|
|
|
* |
334
|
|
|
* |
335
|
|
|
* @param string|bool $locale Locale to adapt |
336
|
|
|
* @param string $transKeyName Translation key name of the url to adapt |
337
|
|
|
* @param array $attributes Attributes for the route (only needed if transKeyName needs them) |
338
|
|
|
* @param bool $forceDefaultLocation Force to show default location even hideDefaultLocaleInURL set as TRUE |
339
|
|
|
* |
340
|
|
|
* @throws SupportedLocalesNotDefined |
341
|
|
|
* @throws UnsupportedLocaleException |
342
|
|
|
* |
343
|
|
|
* @return string|false URL translated |
344
|
|
|
*/ |
345
|
|
|
public function getURLFromRouteNameTranslated($locale, $transKeyName, $attributes = [], $forceDefaultLocation = false) |
346
|
|
|
{ |
347
|
|
|
if (!$this->checkLocaleInSupportedLocales($locale)) { |
348
|
|
|
throw new UnsupportedLocaleException('Locale \''.$locale.'\' is not in the list of supported locales.'); |
349
|
|
|
} |
350
|
|
|
|
351
|
|
|
if (!\is_string($locale)) { |
352
|
|
|
$locale = $this->getDefaultLocale(); |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
$route = ''; |
356
|
|
|
|
357
|
|
|
if ($forceDefaultLocation || !($locale === $this->defaultLocale && $this->hideDefaultLocaleInURL())) { |
358
|
|
|
$route = '/'.$locale; |
359
|
|
|
} |
360
|
|
|
if (\is_string($locale) && $this->translator->has($transKeyName, $locale)) { |
361
|
|
|
$translation = $this->translator->trans($transKeyName, [], $locale); |
362
|
|
|
$route .= '/'.$translation; |
363
|
|
|
|
364
|
|
|
$route = $this->substituteAttributesInRoute($attributes, $route); |
365
|
|
|
} |
366
|
|
|
|
367
|
|
|
if (empty($route)) { |
368
|
|
|
// This locale does not have any key for this route name |
369
|
|
|
return false; |
370
|
|
|
} |
371
|
|
|
|
372
|
|
|
return rtrim($this->createUrlFromUri($route), '/'); |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
/** |
376
|
|
|
* It returns an URL without locale (if it has it) |
377
|
|
|
* Convenience function wrapping getLocalizedURL(false). |
378
|
|
|
* |
379
|
|
|
* @param string|false $url URL to clean, if false, current url would be taken |
380
|
|
|
* |
381
|
|
|
* @return string URL with no locale in path |
382
|
|
|
*/ |
383
|
|
|
public function getNonLocalizedURL($url = null) |
384
|
|
|
{ |
385
|
|
|
return $this->getLocalizedURL(false, $url); |
386
|
|
|
} |
387
|
|
|
|
388
|
|
|
/** |
389
|
|
|
* Returns default locale. |
390
|
|
|
* |
391
|
|
|
* @return string |
392
|
|
|
*/ |
393
|
|
|
public function getDefaultLocale() |
394
|
|
|
{ |
395
|
|
|
return $this->defaultLocale; |
396
|
|
|
} |
397
|
|
|
|
398
|
|
|
/** |
399
|
|
|
* Return an array of all supported Locales. |
400
|
|
|
* |
401
|
|
|
* @throws SupportedLocalesNotDefined |
402
|
|
|
* |
403
|
|
|
* @return array |
404
|
|
|
*/ |
405
|
|
|
public function getSupportedLocales() |
406
|
|
|
{ |
407
|
|
|
if (!empty($this->supportedLocales)) { |
408
|
|
|
return $this->supportedLocales; |
409
|
|
|
} |
410
|
|
|
|
411
|
|
|
$locales = $this->configRepository->get('laravellocalization.supportedLocales'); |
412
|
|
|
|
413
|
|
|
if (empty($locales) || !\is_array($locales)) { |
414
|
|
|
throw new SupportedLocalesNotDefined(); |
415
|
|
|
} |
416
|
|
|
|
417
|
|
|
$this->supportedLocales = $locales; |
418
|
|
|
|
419
|
|
|
return $locales; |
420
|
|
|
} |
421
|
|
|
|
422
|
|
|
/** |
423
|
|
|
* Return an array of all supported Locales but in the order the user |
424
|
|
|
* has specified in the config file. Useful for the language selector. |
425
|
|
|
* |
426
|
|
|
* @return array |
427
|
|
|
*/ |
428
|
|
|
public function getLocalesOrder() |
429
|
|
|
{ |
430
|
|
|
$locales = $this->getSupportedLocales(); |
431
|
|
|
|
432
|
|
|
$order = $this->configRepository->get('laravellocalization.localesOrder'); |
433
|
|
|
|
434
|
|
|
uksort($locales, function ($a, $b) use ($order) { |
435
|
|
|
$pos_a = array_search($a, $order); |
436
|
|
|
$pos_b = array_search($b, $order); |
437
|
|
|
return $pos_a - $pos_b; |
438
|
|
|
}); |
439
|
|
|
|
440
|
|
|
return $locales; |
441
|
|
|
} |
442
|
|
|
|
443
|
|
|
/** |
444
|
|
|
* Returns current locale name. |
445
|
|
|
* |
446
|
|
|
* @return string current locale name |
447
|
|
|
*/ |
448
|
|
|
public function getCurrentLocaleName() |
449
|
|
|
{ |
450
|
|
|
return $this->supportedLocales[$this->getCurrentLocale()]['name']; |
451
|
|
|
} |
452
|
|
|
|
453
|
|
|
/** |
454
|
|
|
* Returns current locale native name. |
455
|
|
|
* |
456
|
|
|
* @return string current locale native name |
457
|
|
|
*/ |
458
|
|
|
public function getCurrentLocaleNative() |
459
|
|
|
{ |
460
|
|
|
return $this->supportedLocales[$this->getCurrentLocale()]['native']; |
461
|
|
|
} |
462
|
|
|
|
463
|
|
|
/** |
464
|
|
|
* Returns current locale direction. |
465
|
|
|
* |
466
|
|
|
* @return string current locale direction |
467
|
|
|
*/ |
468
|
|
|
public function getCurrentLocaleDirection() |
469
|
|
|
{ |
470
|
|
|
if (!empty($this->supportedLocales[$this->getCurrentLocale()]['dir'])) { |
471
|
|
|
return $this->supportedLocales[$this->getCurrentLocale()]['dir']; |
472
|
|
|
} |
473
|
|
|
|
474
|
|
|
switch ($this->getCurrentLocaleScript()) { |
475
|
|
|
// Other (historic) RTL scripts exist, but this list contains the only ones in current use. |
476
|
|
|
case 'Arab': |
477
|
|
|
case 'Hebr': |
478
|
|
|
case 'Mong': |
479
|
|
|
case 'Tfng': |
480
|
|
|
case 'Thaa': |
481
|
|
|
return 'rtl'; |
482
|
|
|
default: |
483
|
|
|
return 'ltr'; |
484
|
|
|
} |
485
|
|
|
} |
486
|
|
|
|
487
|
|
|
/** |
488
|
|
|
* Returns current locale script. |
489
|
|
|
* |
490
|
|
|
* @return string current locale script |
491
|
|
|
*/ |
492
|
|
|
public function getCurrentLocaleScript() |
493
|
|
|
{ |
494
|
|
|
return $this->supportedLocales[$this->getCurrentLocale()]['script']; |
495
|
|
|
} |
496
|
|
|
|
497
|
|
|
/** |
498
|
|
|
* Returns current language's native reading. |
499
|
|
|
* |
500
|
|
|
* @return string current language's native reading |
501
|
|
|
*/ |
502
|
|
|
public function getCurrentLocaleNativeReading() |
503
|
|
|
{ |
504
|
|
|
return $this->supportedLocales[$this->getCurrentLocale()]['native']; |
505
|
|
|
} |
506
|
|
|
|
507
|
|
|
/** |
508
|
|
|
* Returns current language. |
509
|
|
|
* |
510
|
|
|
* @return string current language |
511
|
|
|
*/ |
512
|
|
|
public function getCurrentLocale() |
513
|
|
|
{ |
514
|
|
|
if ($this->currentLocale) { |
515
|
|
|
return $this->currentLocale; |
516
|
|
|
} |
517
|
|
|
|
518
|
|
|
if ($this->useAcceptLanguageHeader() && !$this->app->runningInConsole()) { |
519
|
|
|
$negotiator = new LanguageNegotiator($this->defaultLocale, $this->getSupportedLocales(), $this->request); |
520
|
|
|
|
521
|
|
|
return $negotiator->negotiateLanguage(); |
522
|
|
|
} |
523
|
|
|
|
524
|
|
|
// or get application default language |
525
|
|
|
return $this->configRepository->get('app.locale'); |
526
|
|
|
} |
527
|
|
|
|
528
|
|
|
/** |
529
|
|
|
* Returns current regional. |
530
|
|
|
* |
531
|
|
|
* @return string current regional |
532
|
|
|
*/ |
533
|
|
|
public function getCurrentLocaleRegional() |
534
|
|
|
{ |
535
|
|
|
// need to check if it exists, since 'regional' has been added |
536
|
|
|
// after version 1.0.11 and existing users will not have it |
537
|
|
|
if (isset($this->supportedLocales[$this->getCurrentLocale()]['regional'])) { |
538
|
|
|
return $this->supportedLocales[$this->getCurrentLocale()]['regional']; |
539
|
|
|
} else { |
540
|
|
|
return; |
541
|
|
|
} |
542
|
|
|
} |
543
|
|
|
|
544
|
|
|
/** |
545
|
|
|
* Returns supported languages language key. |
546
|
|
|
* |
547
|
|
|
* @return array keys of supported languages |
548
|
|
|
*/ |
549
|
|
|
public function getSupportedLanguagesKeys() |
550
|
|
|
{ |
551
|
|
|
return array_keys($this->supportedLocales); |
552
|
|
|
} |
553
|
|
|
|
554
|
|
|
/** |
555
|
|
|
* Check if Locale exists on the supported locales array. |
556
|
|
|
* |
557
|
|
|
* @param string|bool $locale string|bool Locale to be checked |
558
|
|
|
* |
559
|
|
|
* @throws SupportedLocalesNotDefined |
560
|
|
|
* |
561
|
|
|
* @return bool is the locale supported? |
562
|
|
|
*/ |
563
|
|
|
public function checkLocaleInSupportedLocales($locale) |
564
|
|
|
{ |
565
|
|
|
$locales = $this->getSupportedLocales(); |
566
|
|
|
if ($locale !== false && empty($locales[$locale])) { |
567
|
|
|
return false; |
568
|
|
|
} |
569
|
|
|
|
570
|
|
|
return true; |
571
|
|
|
} |
572
|
|
|
|
573
|
|
|
/** |
574
|
|
|
* Change route attributes for the ones in the $attributes array. |
575
|
|
|
* |
576
|
|
|
* @param $attributes array Array of attributes |
577
|
|
|
* @param string $route string route to substitute |
578
|
|
|
* |
579
|
|
|
* @return string route with attributes changed |
580
|
|
|
*/ |
581
|
|
|
protected function substituteAttributesInRoute($attributes, $route) |
582
|
|
|
{ |
583
|
|
|
foreach ($attributes as $key => $value) { |
584
|
|
|
if ($value instanceOf UrlRoutable) { |
585
|
|
|
$value = $value->getRouteKey(); |
586
|
|
|
} |
587
|
|
|
$route = str_replace(array('{'.$key.'}', '{'.$key.'?}'), $value, $route); |
588
|
|
|
} |
589
|
|
|
|
590
|
|
|
// delete empty optional arguments that are not in the $attributes array |
591
|
|
|
$route = preg_replace('/\/{[^)]+\?}/', '', $route); |
592
|
|
|
|
593
|
|
|
return $route; |
594
|
|
|
} |
595
|
|
|
|
596
|
|
|
/** |
597
|
|
|
* Returns translated routes. |
598
|
|
|
* |
599
|
|
|
* @return array translated routes |
600
|
|
|
*/ |
601
|
|
|
protected function getTranslatedRoutes() |
602
|
|
|
{ |
603
|
|
|
return $this->translatedRoutes; |
604
|
|
|
} |
605
|
|
|
|
606
|
|
|
/** |
607
|
|
|
* Set current route name. |
608
|
|
|
* |
609
|
|
|
* @param string $routeName current route name |
610
|
|
|
*/ |
611
|
|
|
public function setRouteName($routeName) |
612
|
|
|
{ |
613
|
|
|
$this->routeName = $routeName; |
614
|
|
|
} |
615
|
|
|
|
616
|
|
|
/** |
617
|
|
|
* Translate routes and save them to the translated routes array (used in the localize route filter). |
618
|
|
|
* |
619
|
|
|
* @param string $routeName Key of the translated string |
620
|
|
|
* |
621
|
|
|
* @return string Translated string |
622
|
|
|
*/ |
623
|
|
|
public function transRoute($routeName) |
624
|
|
|
{ |
625
|
|
|
if (!\in_array($routeName, $this->translatedRoutes)) { |
626
|
|
|
$this->translatedRoutes[] = $routeName; |
627
|
|
|
} |
628
|
|
|
|
629
|
|
|
return $this->translator->trans($routeName); |
630
|
|
|
} |
631
|
|
|
|
632
|
|
|
/** |
633
|
|
|
* Returns the translation key for a given path. |
634
|
|
|
* |
635
|
|
|
* @param string $path Path to get the key translated |
636
|
|
|
* |
637
|
|
|
* @return string|false Key for translation, false if not exist |
638
|
|
|
*/ |
639
|
|
|
public function getRouteNameFromAPath($path) |
640
|
|
|
{ |
641
|
|
|
$attributes = $this->extractAttributes($path); |
642
|
|
|
|
643
|
|
|
$path = parse_url($path)['path']; |
644
|
|
|
$path = trim(str_replace('/'.$this->currentLocale.'/', '', $path), "/"); |
645
|
|
|
|
646
|
|
|
foreach ($this->translatedRoutes as $route) { |
647
|
|
|
if (trim($this->substituteAttributesInRoute($attributes, $this->translator->trans($route)), '/') === $path) { |
|
|
|
|
648
|
|
|
return $route; |
649
|
|
|
} |
650
|
|
|
} |
651
|
|
|
|
652
|
|
|
return false; |
653
|
|
|
} |
654
|
|
|
|
655
|
|
|
/** |
656
|
|
|
* Returns the translated route for the path and the url given. |
657
|
|
|
* |
658
|
|
|
* @param string $path Path to check if it is a translated route |
659
|
|
|
* @param string $url_locale Language to check if the path exists |
660
|
|
|
* |
661
|
|
|
* @return string|false Key for translation, false if not exist |
662
|
|
|
*/ |
663
|
|
|
protected function findTranslatedRouteByPath($path, $url_locale) |
664
|
|
|
{ |
665
|
|
|
// check if this url is a translated url |
666
|
|
|
foreach ($this->translatedRoutes as $translatedRoute) { |
667
|
|
|
if ($this->translator->trans($translatedRoute, [], $url_locale) == rawurldecode($path)) { |
668
|
|
|
return $translatedRoute; |
669
|
|
|
} |
670
|
|
|
} |
671
|
|
|
|
672
|
|
|
return false; |
673
|
|
|
} |
674
|
|
|
|
675
|
|
|
/** |
676
|
|
|
* Returns the translated route for an url and the attributes given and a locale. |
677
|
|
|
* |
678
|
|
|
* |
679
|
|
|
* @param string|false|null $url Url to check if it is a translated route |
680
|
|
|
* @param array $attributes Attributes to check if the url exists in the translated routes array |
681
|
|
|
* @param string $locale Language to check if the url exists |
682
|
|
|
* |
683
|
|
|
* @throws SupportedLocalesNotDefined |
684
|
|
|
* @throws UnsupportedLocaleException |
685
|
|
|
* |
686
|
|
|
* @return string|false Key for translation, false if not exist |
687
|
|
|
*/ |
688
|
|
|
protected function findTranslatedRouteByUrl($url, $attributes, $locale) |
689
|
|
|
{ |
690
|
|
|
if (empty($url)) { |
691
|
|
|
return false; |
692
|
|
|
} |
693
|
|
|
|
694
|
|
|
if (isset($this->cachedTranslatedRoutesByUrl[$locale][$url])) { |
695
|
|
|
return $this->cachedTranslatedRoutesByUrl[$locale][$url]; |
696
|
|
|
} |
697
|
|
|
|
698
|
|
|
// check if this url is a translated url |
699
|
|
|
foreach ($this->translatedRoutes as $translatedRoute) { |
700
|
|
|
$routeName = $this->getURLFromRouteNameTranslated($locale, $translatedRoute, $attributes); |
701
|
|
|
|
702
|
|
|
// We can ignore extra url parts and compare only their url_path (ignore arguments that are not attributes) |
703
|
|
|
if (parse_url($this->getNonLocalizedURL($routeName), PHP_URL_PATH) == parse_url($this->getNonLocalizedURL($url), PHP_URL_PATH)) { |
704
|
|
|
$this->cachedTranslatedRoutesByUrl[$locale][$url] = $translatedRoute; |
705
|
|
|
|
706
|
|
|
return $translatedRoute; |
707
|
|
|
} |
708
|
|
|
} |
709
|
|
|
|
710
|
|
|
return false; |
711
|
|
|
} |
712
|
|
|
|
713
|
|
|
/** |
714
|
|
|
* Returns true if the string given is a valid url. |
715
|
|
|
* |
716
|
|
|
* @param string $url String to check if it is a valid url |
717
|
|
|
* |
718
|
|
|
* @return bool Is the string given a valid url? |
719
|
|
|
*/ |
720
|
|
|
protected function checkUrl($url) |
721
|
|
|
{ |
722
|
|
|
return filter_var($url, FILTER_VALIDATE_URL); |
723
|
|
|
} |
724
|
|
|
|
725
|
|
|
/** |
726
|
|
|
* Returns the config repository for this instance. |
727
|
|
|
* |
728
|
|
|
* @return Repository Configuration repository |
729
|
|
|
*/ |
730
|
|
|
public function getConfigRepository() |
731
|
|
|
{ |
732
|
|
|
return $this->configRepository; |
733
|
|
|
} |
734
|
|
|
|
735
|
|
|
/** |
736
|
|
|
* Returns the translation key for a given path. |
737
|
|
|
* |
738
|
|
|
* @return bool Returns value of useAcceptLanguageHeader in config. |
739
|
|
|
*/ |
740
|
|
|
protected function useAcceptLanguageHeader() |
741
|
|
|
{ |
742
|
|
|
return $this->configRepository->get('laravellocalization.useAcceptLanguageHeader'); |
743
|
|
|
} |
744
|
|
|
|
745
|
|
|
public function hideUrlAndAcceptHeader() |
746
|
|
|
{ |
747
|
|
|
return $this->hideDefaultLocaleInURL() && $this->useAcceptLanguageHeader(); |
748
|
|
|
} |
749
|
|
|
|
750
|
|
|
/** |
751
|
|
|
* Returns the translation key for a given path. |
752
|
|
|
* |
753
|
|
|
* @return bool Returns value of hideDefaultLocaleInURL in config. |
754
|
|
|
*/ |
755
|
|
|
public function hideDefaultLocaleInURL() |
756
|
|
|
{ |
757
|
|
|
return $this->configRepository->get('laravellocalization.hideDefaultLocaleInURL'); |
758
|
|
|
} |
759
|
|
|
|
760
|
|
|
/** |
761
|
|
|
* Create an url from the uri. |
762
|
|
|
* |
763
|
|
|
* @param string $uri Uri |
764
|
|
|
* |
765
|
|
|
* @return string Url for the given uri |
766
|
|
|
*/ |
767
|
|
|
public function createUrlFromUri($uri) |
768
|
|
|
{ |
769
|
|
|
$uri = ltrim($uri, '/'); |
770
|
|
|
|
771
|
|
|
if (empty($this->baseUrl)) { |
772
|
|
|
return app('url')->to($uri); |
773
|
|
|
} |
774
|
|
|
|
775
|
|
|
return $this->baseUrl.$uri; |
776
|
|
|
} |
777
|
|
|
|
778
|
|
|
/** |
779
|
|
|
* Sets the base url for the site. |
780
|
|
|
* |
781
|
|
|
* @param string $url Base url for the site |
782
|
|
|
*/ |
783
|
|
|
public function setBaseUrl($url) |
784
|
|
|
{ |
785
|
|
|
if (substr($url, -1) != '/') { |
786
|
|
|
$url .= '/'; |
787
|
|
|
} |
788
|
|
|
|
789
|
|
|
$this->baseUrl = $url; |
790
|
|
|
} |
791
|
|
|
|
792
|
|
|
/** |
793
|
|
|
* Returns serialized translated routes for caching purposes. |
794
|
|
|
* |
795
|
|
|
* @return string |
796
|
|
|
*/ |
797
|
|
|
public function getSerializedTranslatedRoutes() |
798
|
|
|
{ |
799
|
|
|
return base64_encode(serialize($this->translatedRoutes)); |
800
|
|
|
} |
801
|
|
|
|
802
|
|
|
/** |
803
|
|
|
* Sets the translated routes list. |
804
|
|
|
* Only useful from a cached routes context. |
805
|
|
|
* |
806
|
|
|
* @param string $serializedRoutes |
807
|
|
|
*/ |
808
|
|
|
public function setSerializedTranslatedRoutes($serializedRoutes) |
809
|
|
|
{ |
810
|
|
|
if ( ! $serializedRoutes) { |
811
|
|
|
return; |
812
|
|
|
} |
813
|
|
|
|
814
|
|
|
$this->translatedRoutes = unserialize(base64_decode($serializedRoutes)); |
815
|
|
|
} |
816
|
|
|
|
817
|
|
|
/** |
818
|
|
|
* Extract attributes for current url. |
819
|
|
|
* |
820
|
|
|
* @param bool|false|null|string $url to extract attributes, if not present, the system will look for attributes in the current call |
821
|
|
|
* @param string $locale |
822
|
|
|
* |
823
|
|
|
* @return array Array with attributes |
824
|
|
|
*/ |
825
|
|
|
protected function extractAttributes($url = false, $locale = '') |
826
|
|
|
{ |
827
|
|
|
if (!empty($url)) { |
828
|
|
|
$attributes = []; |
829
|
|
|
$parse = parse_url($url); |
830
|
|
|
if (isset($parse['path'])) { |
831
|
|
|
$parse['path'] = trim(str_replace('/'.$this->currentLocale.'/', '', $parse['path']), "/"); |
832
|
|
|
$url = explode('/', trim($parse['path'], '/')); |
833
|
|
|
} else { |
834
|
|
|
$url = []; |
835
|
|
|
} |
836
|
|
|
|
837
|
|
|
foreach ($this->router->getRoutes() as $route) { |
838
|
|
|
$attributes = []; |
839
|
|
|
$path = method_exists($route, 'uri') ? $route->uri() : $route->getUri(); |
840
|
|
|
|
841
|
|
|
if (!preg_match("/{[\w]+\??}/", $path)) { |
842
|
|
|
continue; |
843
|
|
|
} |
844
|
|
|
|
845
|
|
|
$path = explode('/', $path); |
846
|
|
|
$i = 0; |
847
|
|
|
|
848
|
|
|
// The system's route can't be smaller |
849
|
|
|
// only the $url can be missing segments (optional parameters) |
850
|
|
|
// We can assume it's the wrong route |
851
|
|
|
if (count($path) < count($url)) { |
852
|
|
|
continue; |
853
|
|
|
} |
854
|
|
|
|
855
|
|
|
$match = true; |
856
|
|
|
foreach ($path as $j => $segment) { |
857
|
|
|
if (isset($url[$i])) { |
858
|
|
|
if ($segment === $url[$i]) { |
859
|
|
|
$i++; |
860
|
|
|
continue; |
861
|
|
View Code Duplication |
} elseif (preg_match("/{[\w]+}/", $segment)) { |
|
|
|
|
862
|
|
|
// must-have parameters |
863
|
|
|
$attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment); |
864
|
|
|
$attributes[$attribute_name] = $url[$i]; |
865
|
|
|
$i++; |
866
|
|
|
continue; |
867
|
|
|
} elseif (preg_match("/{[\w]+\?}/", $segment)) { |
868
|
|
|
// optional parameters |
869
|
|
|
if (!isset($path[$j + 1]) || $path[$j + 1] !== $url[$i]) { |
870
|
|
|
// optional parameter taken |
871
|
|
|
$attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment); |
872
|
|
|
$attributes[$attribute_name] = $url[$i]; |
873
|
|
|
$i++; |
874
|
|
|
continue; |
875
|
|
|
} else { |
876
|
|
|
$match = false; |
877
|
|
|
break; |
878
|
|
|
} |
879
|
|
|
} else { |
880
|
|
|
// As soon as one segment doesn't match, then we have the wrong route |
881
|
|
|
$match = false; |
882
|
|
|
break; |
883
|
|
|
} |
884
|
|
View Code Duplication |
} elseif (preg_match("/{[\w]+\?}/", $segment)) { |
|
|
|
|
885
|
|
|
$attribute_name = preg_replace(['/}/', '/{/', "/\?/"], '', $segment); |
886
|
|
|
$attributes[$attribute_name] = null; |
887
|
|
|
$i++; |
888
|
|
|
} else { |
889
|
|
|
// no optional parameters but no more $url given |
890
|
|
|
// this route does not match the url |
891
|
|
|
$match = false; |
892
|
|
|
break; |
893
|
|
|
} |
894
|
|
|
} |
895
|
|
|
|
896
|
|
|
if (isset($url[$i + 1])) { |
897
|
|
|
$match = false; |
898
|
|
|
} |
899
|
|
|
|
900
|
|
|
if ($match) { |
901
|
|
|
return $attributes; |
902
|
|
|
} |
903
|
|
|
} |
904
|
|
|
} else { |
905
|
|
|
if (!$this->router->current()) { |
906
|
|
|
return []; |
907
|
|
|
} |
908
|
|
|
|
909
|
|
|
$attributes = $this->normalizeAttributes($this->router->current()->parameters()); |
910
|
|
|
$response = event('routes.translation', [$locale, $attributes]); |
911
|
|
|
|
912
|
|
|
if (!empty($response)) { |
913
|
|
|
$response = array_shift($response); |
914
|
|
|
} |
915
|
|
|
|
916
|
|
|
if (\is_array($response)) { |
917
|
|
|
$attributes = array_merge($attributes, $response); |
918
|
|
|
} |
919
|
|
|
} |
920
|
|
|
|
921
|
|
|
return $attributes; |
922
|
|
|
} |
923
|
|
|
|
924
|
|
|
/** |
925
|
|
|
* Build URL using array data from parse_url. |
926
|
|
|
* |
927
|
|
|
* @param array|false $parsed_url Array of data from parse_url function |
928
|
|
|
* |
929
|
|
|
* @return string Returns URL as string. |
930
|
|
|
*/ |
931
|
|
|
protected function unparseUrl($parsed_url) |
932
|
|
|
{ |
933
|
|
|
if (empty($parsed_url)) { |
934
|
|
|
return ''; |
935
|
|
|
} |
936
|
|
|
|
937
|
|
|
$url = ''; |
938
|
|
|
$url .= isset($parsed_url['scheme']) ? $parsed_url['scheme'].'://' : ''; |
939
|
|
|
$url .= $parsed_url['host'] ?? ''; |
940
|
|
|
$url .= isset($parsed_url['port']) ? ':'.$parsed_url['port'] : ''; |
941
|
|
|
$user = $parsed_url['user'] ?? ''; |
942
|
|
|
$pass = isset($parsed_url['pass']) ? ':'.$parsed_url['pass'] : ''; |
943
|
|
|
$url .= $user.(($user || $pass) ? "$pass@" : ''); |
944
|
|
|
|
945
|
|
|
if (!empty($url)) { |
946
|
|
|
$url .= isset($parsed_url['path']) ? '/'.ltrim($parsed_url['path'], '/') : ''; |
947
|
|
|
} else { |
948
|
|
|
$url .= $parsed_url['path'] ?? ''; |
949
|
|
|
} |
950
|
|
|
|
951
|
|
|
$url .= isset($parsed_url['query']) ? '?'.$parsed_url['query'] : ''; |
952
|
|
|
$url .= isset($parsed_url['fragment']) ? '#'.$parsed_url['fragment'] : ''; |
953
|
|
|
|
954
|
|
|
return $url; |
955
|
|
|
} |
956
|
|
|
|
957
|
|
|
/** |
958
|
|
|
* Normalize attributes gotten from request parameters. |
959
|
|
|
* |
960
|
|
|
* @param array $attributes The attributes |
961
|
|
|
* @return array The normalized attributes |
962
|
|
|
*/ |
963
|
|
|
protected function normalizeAttributes($attributes) |
964
|
|
|
{ |
965
|
|
|
if (array_key_exists('data', $attributes) && \is_array($attributes['data']) && ! \count($attributes['data'])) { |
966
|
|
|
$attributes['data'] = null; |
967
|
|
|
return $attributes; |
968
|
|
|
} |
969
|
|
|
return $attributes; |
970
|
|
|
} |
971
|
|
|
|
972
|
|
|
/** |
973
|
|
|
* Returns the forced environment set route locale. |
974
|
|
|
* |
975
|
|
|
* @return string|null |
976
|
|
|
*/ |
977
|
|
|
protected function getForcedLocale() |
978
|
|
|
{ |
979
|
|
|
return env(static::ENV_ROUTE_KEY, function () { |
980
|
|
|
$value = getenv(static::ENV_ROUTE_KEY); |
981
|
|
|
|
982
|
|
|
if ($value !== false) { |
983
|
|
|
return $value; |
984
|
|
|
} |
985
|
|
|
}); |
986
|
|
|
} |
987
|
|
|
} |
988
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.