Subversion-Projekte lars-tiefland.laravel_shop

Revision

Revision 148 | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Translation;
4
 
399 lars 5
use Closure;
148 lars 6
use Illuminate\Contracts\Translation\Loader;
7
use Illuminate\Contracts\Translation\Translator as TranslatorContract;
8
use Illuminate\Support\Arr;
9
use Illuminate\Support\NamespacedItemResolver;
10
use Illuminate\Support\Str;
11
use Illuminate\Support\Traits\Macroable;
399 lars 12
use Illuminate\Support\Traits\ReflectsClosures;
148 lars 13
use InvalidArgumentException;
14
 
15
class Translator extends NamespacedItemResolver implements TranslatorContract
16
{
399 lars 17
    use Macroable, ReflectsClosures;
148 lars 18
 
19
    /**
20
     * The loader implementation.
21
     *
22
     * @var \Illuminate\Contracts\Translation\Loader
23
     */
24
    protected $loader;
25
 
26
    /**
27
     * The default locale being used by the translator.
28
     *
29
     * @var string
30
     */
31
    protected $locale;
32
 
33
    /**
34
     * The fallback locale used by the translator.
35
     *
36
     * @var string
37
     */
38
    protected $fallback;
39
 
40
    /**
41
     * The array of loaded translation groups.
42
     *
43
     * @var array
44
     */
45
    protected $loaded = [];
46
 
47
    /**
48
     * The message selector.
49
     *
50
     * @var \Illuminate\Translation\MessageSelector
51
     */
52
    protected $selector;
53
 
54
    /**
55
     * The callable that should be invoked to determine applicable locales.
56
     *
57
     * @var callable
58
     */
59
    protected $determineLocalesUsing;
60
 
61
    /**
399 lars 62
     * The custom rendering callbacks for stringable objects.
63
     *
64
     * @var array
65
     */
66
    protected $stringableHandlers = [];
67
 
68
    /**
148 lars 69
     * Create a new translator instance.
70
     *
71
     * @param  \Illuminate\Contracts\Translation\Loader  $loader
72
     * @param  string  $locale
73
     * @return void
74
     */
75
    public function __construct(Loader $loader, $locale)
76
    {
77
        $this->loader = $loader;
78
 
79
        $this->setLocale($locale);
80
    }
81
 
82
    /**
83
     * Determine if a translation exists for a given locale.
84
     *
85
     * @param  string  $key
86
     * @param  string|null  $locale
87
     * @return bool
88
     */
89
    public function hasForLocale($key, $locale = null)
90
    {
91
        return $this->has($key, $locale, false);
92
    }
93
 
94
    /**
95
     * Determine if a translation exists.
96
     *
97
     * @param  string  $key
98
     * @param  string|null  $locale
99
     * @param  bool  $fallback
100
     * @return bool
101
     */
102
    public function has($key, $locale = null, $fallback = true)
103
    {
104
        return $this->get($key, [], $locale, $fallback) !== $key;
105
    }
106
 
107
    /**
108
     * Get the translation for the given key.
109
     *
110
     * @param  string  $key
111
     * @param  array  $replace
112
     * @param  string|null  $locale
113
     * @param  bool  $fallback
114
     * @return string|array
115
     */
116
    public function get($key, array $replace = [], $locale = null, $fallback = true)
117
    {
118
        $locale = $locale ?: $this->locale;
119
 
120
        // For JSON translations, there is only one file per locale, so we will simply load
121
        // that file and then we will be ready to check the array for the key. These are
122
        // only one level deep so we do not need to do any fancy searching through it.
123
        $this->load('*', '*', $locale);
124
 
125
        $line = $this->loaded['*']['*'][$locale][$key] ?? null;
126
 
127
        // If we can't find a translation for the JSON key, we will attempt to translate it
128
        // using the typical translation file. This way developers can always just use a
129
        // helper such as __ instead of having to pick between trans or __ with views.
130
        if (! isset($line)) {
131
            [$namespace, $group, $item] = $this->parseKey($key);
132
 
133
            // Here we will get the locale that should be used for the language line. If one
134
            // was not passed, we will use the default locales which was given to us when
135
            // the translator was instantiated. Then, we can load the lines and return.
136
            $locales = $fallback ? $this->localeArray($locale) : [$locale];
137
 
138
            foreach ($locales as $locale) {
139
                if (! is_null($line = $this->getLine(
140
                    $namespace, $group, $locale, $item, $replace
141
                ))) {
142
                    return $line;
143
                }
144
            }
145
        }
146
 
147
        // If the line doesn't exist, we will return back the key which was requested as
148
        // that will be quick to spot in the UI if language keys are wrong or missing
149
        // from the application's language files. Otherwise we can return the line.
150
        return $this->makeReplacements($line ?: $key, $replace);
151
    }
152
 
153
    /**
154
     * Get a translation according to an integer value.
155
     *
156
     * @param  string  $key
157
     * @param  \Countable|int|array  $number
158
     * @param  array  $replace
159
     * @param  string|null  $locale
160
     * @return string
161
     */
162
    public function choice($key, $number, array $replace = [], $locale = null)
163
    {
164
        $line = $this->get(
165
            $key, $replace, $locale = $this->localeForChoice($locale)
166
        );
167
 
168
        // If the given "number" is actually an array or countable we will simply count the
169
        // number of elements in an instance. This allows developers to pass an array of
170
        // items without having to count it on their end first which gives bad syntax.
171
        if (is_countable($number)) {
172
            $number = count($number);
173
        }
174
 
175
        $replace['count'] = $number;
176
 
177
        return $this->makeReplacements(
178
            $this->getSelector()->choose($line, $number, $locale), $replace
179
        );
180
    }
181
 
182
    /**
183
     * Get the proper locale for a choice operation.
184
     *
185
     * @param  string|null  $locale
186
     * @return string
187
     */
188
    protected function localeForChoice($locale)
189
    {
190
        return $locale ?: $this->locale ?: $this->fallback;
191
    }
192
 
193
    /**
194
     * Retrieve a language line out the loaded array.
195
     *
196
     * @param  string  $namespace
197
     * @param  string  $group
198
     * @param  string  $locale
199
     * @param  string  $item
200
     * @param  array  $replace
201
     * @return string|array|null
202
     */
203
    protected function getLine($namespace, $group, $locale, $item, array $replace)
204
    {
205
        $this->load($namespace, $group, $locale);
206
 
207
        $line = Arr::get($this->loaded[$namespace][$group][$locale], $item);
208
 
209
        if (is_string($line)) {
210
            return $this->makeReplacements($line, $replace);
211
        } elseif (is_array($line) && count($line) > 0) {
212
            array_walk_recursive($line, function (&$value, $key) use ($replace) {
213
                $value = $this->makeReplacements($value, $replace);
214
            });
215
 
216
            return $line;
217
        }
218
    }
219
 
220
    /**
221
     * Make the place-holder replacements on a line.
222
     *
223
     * @param  string  $line
224
     * @param  array  $replace
225
     * @return string
226
     */
227
    protected function makeReplacements($line, array $replace)
228
    {
229
        if (empty($replace)) {
230
            return $line;
231
        }
232
 
233
        $shouldReplace = [];
234
 
235
        foreach ($replace as $key => $value) {
399 lars 236
            if (is_object($value) && isset($this->stringableHandlers[get_class($value)])) {
237
                $value = call_user_func($this->stringableHandlers[get_class($value)], $value);
238
            }
239
 
148 lars 240
            $shouldReplace[':'.Str::ucfirst($key ?? '')] = Str::ucfirst($value ?? '');
241
            $shouldReplace[':'.Str::upper($key ?? '')] = Str::upper($value ?? '');
242
            $shouldReplace[':'.$key] = $value;
243
        }
244
 
245
        return strtr($line, $shouldReplace);
246
    }
247
 
248
    /**
249
     * Add translation lines to the given locale.
250
     *
251
     * @param  array  $lines
252
     * @param  string  $locale
253
     * @param  string  $namespace
254
     * @return void
255
     */
256
    public function addLines(array $lines, $locale, $namespace = '*')
257
    {
258
        foreach ($lines as $key => $value) {
259
            [$group, $item] = explode('.', $key, 2);
260
 
261
            Arr::set($this->loaded, "$namespace.$group.$locale.$item", $value);
262
        }
263
    }
264
 
265
    /**
266
     * Load the specified language group.
267
     *
268
     * @param  string  $namespace
269
     * @param  string  $group
270
     * @param  string  $locale
271
     * @return void
272
     */
273
    public function load($namespace, $group, $locale)
274
    {
275
        if ($this->isLoaded($namespace, $group, $locale)) {
276
            return;
277
        }
278
 
279
        // The loader is responsible for returning the array of language lines for the
280
        // given namespace, group, and locale. We'll set the lines in this array of
281
        // lines that have already been loaded so that we can easily access them.
282
        $lines = $this->loader->load($locale, $group, $namespace);
283
 
284
        $this->loaded[$namespace][$group][$locale] = $lines;
285
    }
286
 
287
    /**
288
     * Determine if the given group has been loaded.
289
     *
290
     * @param  string  $namespace
291
     * @param  string  $group
292
     * @param  string  $locale
293
     * @return bool
294
     */
295
    protected function isLoaded($namespace, $group, $locale)
296
    {
297
        return isset($this->loaded[$namespace][$group][$locale]);
298
    }
299
 
300
    /**
301
     * Add a new namespace to the loader.
302
     *
303
     * @param  string  $namespace
304
     * @param  string  $hint
305
     * @return void
306
     */
307
    public function addNamespace($namespace, $hint)
308
    {
309
        $this->loader->addNamespace($namespace, $hint);
310
    }
311
 
312
    /**
313
     * Add a new JSON path to the loader.
314
     *
315
     * @param  string  $path
316
     * @return void
317
     */
318
    public function addJsonPath($path)
319
    {
320
        $this->loader->addJsonPath($path);
321
    }
322
 
323
    /**
324
     * Parse a key into namespace, group, and item.
325
     *
326
     * @param  string  $key
327
     * @return array
328
     */
329
    public function parseKey($key)
330
    {
331
        $segments = parent::parseKey($key);
332
 
333
        if (is_null($segments[0])) {
334
            $segments[0] = '*';
335
        }
336
 
337
        return $segments;
338
    }
339
 
340
    /**
341
     * Get the array of locales to be checked.
342
     *
343
     * @param  string|null  $locale
344
     * @return array
345
     */
346
    protected function localeArray($locale)
347
    {
348
        $locales = array_filter([$locale ?: $this->locale, $this->fallback]);
349
 
350
        return call_user_func($this->determineLocalesUsing ?: fn () => $locales, $locales);
351
    }
352
 
353
    /**
354
     * Specify a callback that should be invoked to determined the applicable locale array.
355
     *
356
     * @param  callable  $callback
357
     * @return void
358
     */
359
    public function determineLocalesUsing($callback)
360
    {
361
        $this->determineLocalesUsing = $callback;
362
    }
363
 
364
    /**
365
     * Get the message selector instance.
366
     *
367
     * @return \Illuminate\Translation\MessageSelector
368
     */
369
    public function getSelector()
370
    {
371
        if (! isset($this->selector)) {
372
            $this->selector = new MessageSelector;
373
        }
374
 
375
        return $this->selector;
376
    }
377
 
378
    /**
379
     * Set the message selector instance.
380
     *
381
     * @param  \Illuminate\Translation\MessageSelector  $selector
382
     * @return void
383
     */
384
    public function setSelector(MessageSelector $selector)
385
    {
386
        $this->selector = $selector;
387
    }
388
 
389
    /**
390
     * Get the language line loader implementation.
391
     *
392
     * @return \Illuminate\Contracts\Translation\Loader
393
     */
394
    public function getLoader()
395
    {
396
        return $this->loader;
397
    }
398
 
399
    /**
400
     * Get the default locale being used.
401
     *
402
     * @return string
403
     */
404
    public function locale()
405
    {
406
        return $this->getLocale();
407
    }
408
 
409
    /**
410
     * Get the default locale being used.
411
     *
412
     * @return string
413
     */
414
    public function getLocale()
415
    {
416
        return $this->locale;
417
    }
418
 
419
    /**
420
     * Set the default locale.
421
     *
422
     * @param  string  $locale
423
     * @return void
424
     *
425
     * @throws \InvalidArgumentException
426
     */
427
    public function setLocale($locale)
428
    {
429
        if (Str::contains($locale, ['/', '\\'])) {
430
            throw new InvalidArgumentException('Invalid characters present in locale.');
431
        }
432
 
433
        $this->locale = $locale;
434
    }
435
 
436
    /**
437
     * Get the fallback locale being used.
438
     *
439
     * @return string
440
     */
441
    public function getFallback()
442
    {
443
        return $this->fallback;
444
    }
445
 
446
    /**
447
     * Set the fallback locale being used.
448
     *
449
     * @param  string  $fallback
450
     * @return void
451
     */
452
    public function setFallback($fallback)
453
    {
454
        $this->fallback = $fallback;
455
    }
456
 
457
    /**
458
     * Set the loaded translation groups.
459
     *
460
     * @param  array  $loaded
461
     * @return void
462
     */
463
    public function setLoaded(array $loaded)
464
    {
465
        $this->loaded = $loaded;
466
    }
399 lars 467
 
468
    /**
469
     * Add a handler to be executed in order to format a given class to a string during translation replacements.
470
     *
471
     * @param  callable|string  $class
472
     * @param  callable|null  $handler
473
     * @return void
474
     */
475
    public function stringable($class, $handler = null)
476
    {
477
        if ($class instanceof Closure) {
478
            [$class, $handler] = [
479
                $this->firstClosureParameterType($class),
480
                $class,
481
            ];
482
        }
483
 
484
        $this->stringableHandlers[$class] = $handler;
485
    }
148 lars 486
}