1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
// +---------------------------------------------------------------------------+ |
4
|
|
|
// | This file is part of the Agavi package. | |
5
|
|
|
// | Copyright (c) 2005-2011 the Agavi Project. | |
6
|
|
|
// | | |
7
|
|
|
// | For the full copyright and license information, please view the LICENSE | |
8
|
|
|
// | file that was distributed with this source code. You can also view the | |
9
|
|
|
// | LICENSE file online at http://www.agavi.org/LICENSE.txt | |
10
|
|
|
// | vi: set noexpandtab: | |
11
|
|
|
// | Local Variables: | |
12
|
|
|
// | indent-tabs-mode: t | |
13
|
|
|
// | End: | |
14
|
|
|
// +---------------------------------------------------------------------------+ |
15
|
|
|
|
16
|
|
|
namespace Agavi\Translation; |
17
|
|
|
|
18
|
|
|
use Agavi\Config\Config; |
19
|
|
|
use Agavi\Config\ConfigCache; |
20
|
|
|
use Agavi\Core\Context; |
21
|
|
|
use Agavi\Date\Calendar; |
22
|
|
|
use Agavi\Date\DateDefinitions; |
23
|
|
|
use Agavi\Date\DateFormat; |
24
|
|
|
use Agavi\Date\GregorianCalendar; |
25
|
|
|
use Agavi\Date\OlsonTimeZone; |
26
|
|
|
use Agavi\Date\TimeZone; |
27
|
|
|
use Agavi\Exception\AgaviException; |
28
|
|
|
use Agavi\Exception\Exception; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* The translation manager manages the interface between the application and the |
32
|
|
|
* current translation engine implementation |
33
|
|
|
* |
34
|
|
|
* @package agavi |
35
|
|
|
* @subpackage translation |
36
|
|
|
* |
37
|
|
|
* @author Dominik del Bondio <[email protected]> |
38
|
|
|
* @copyright Authors |
39
|
|
|
* @copyright The Agavi Project |
40
|
|
|
* |
41
|
|
|
* @since 0.11.0 |
42
|
|
|
* |
43
|
|
|
* @version $Id$ |
44
|
|
|
*/ |
45
|
|
|
class TranslationManager |
46
|
|
|
{ |
47
|
|
|
const MESSAGE = 'msg'; |
48
|
|
|
const NUMBER = 'num'; |
49
|
|
|
const CURRENCY = 'cur'; |
50
|
|
|
const DATETIME = 'date'; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @var Context A Context instance. |
54
|
|
|
*/ |
55
|
|
|
protected $context = null; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* @var array An array of the translator instances for the domains. |
59
|
|
|
*/ |
60
|
|
|
protected $translators = array(); |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* @var Locale The current locale. |
64
|
|
|
*/ |
65
|
|
|
protected $currentLocale = null; |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* @var string The original locale identifier given to this instance. |
69
|
|
|
*/ |
70
|
|
|
protected $givenLocaleIdentifier = null; |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* @var string The identifier of the current locale. |
74
|
|
|
*/ |
75
|
|
|
protected $currentLocaleIdentifier = null; |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* @var string The default locale identifier. |
79
|
|
|
*/ |
80
|
|
|
protected $defaultLocaleIdentifier = null; |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* @var string The default domain which shall be used for translation. |
84
|
|
|
*/ |
85
|
|
|
protected $defaultDomain = null; |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* @var array The available locales which have been defined in the |
89
|
|
|
* translation.xml config file. |
90
|
|
|
*/ |
91
|
|
|
protected $availableConfigLocales = array(); |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* @var array All available locales. Just stores the info for lazyload. |
95
|
|
|
*/ |
96
|
|
|
protected $availableLocales = array(); |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* @var array A cache for locale instances. |
100
|
|
|
*/ |
101
|
|
|
protected $localeCache = array(); |
102
|
|
|
|
103
|
|
|
/** |
104
|
|
|
* @var array A cache for locale identifiers resolved from a string. |
105
|
|
|
*/ |
106
|
|
|
protected $localeIdentifierCache = array(); |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* @var array A cache for the data of the available locales. |
110
|
|
|
*/ |
111
|
|
|
protected $localeDataCache = array(); |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* @var array The supplemental data from the cldr |
115
|
|
|
*/ |
116
|
|
|
protected $supplementalData = array(); |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* @var array The list of available time zones. |
120
|
|
|
*/ |
121
|
|
|
protected $timeZoneList = array(); |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* @var array A cache for the time zone instances. |
125
|
|
|
*/ |
126
|
|
|
protected $timeZoneCache = array(); |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* @var string The default time zone. If not set the timezone php |
130
|
|
|
* will be used as default. |
131
|
|
|
*/ |
132
|
|
|
protected $defaultTimeZone = null; |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* Initialize this TranslationManager. |
136
|
|
|
* |
137
|
|
|
* @param Context $context The current application context. |
138
|
|
|
* @param array $parameters An associative array of initialization parameters. |
139
|
|
|
* |
140
|
|
|
* @author Dominik del Bondio <[email protected]> |
141
|
|
|
* @since 0.11.0 |
142
|
|
|
*/ |
143
|
|
|
public function initialize(Context $context, array $parameters = array()) |
144
|
|
|
{ |
145
|
|
|
$this->context = $context; |
146
|
|
|
|
147
|
|
|
include(ConfigCache::checkConfig(Config::get('core.config_dir') . '/translation.xml')); |
148
|
|
|
$this->loadSupplementalData(); |
149
|
|
|
$this->loadTimeZoneData(); |
150
|
|
|
$this->loadAvailableLocales(); |
151
|
|
|
if ($this->defaultLocaleIdentifier === null) { |
152
|
|
|
throw new AgaviException('Tried to use the translation system without a default locale and without a locale set'); |
153
|
|
|
} |
154
|
|
|
$this->setLocale($this->defaultLocaleIdentifier); |
155
|
|
|
|
156
|
|
|
if ($this->defaultTimeZone === null) { |
157
|
|
|
$this->defaultTimeZone = date_default_timezone_get(); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
if ($this->defaultTimeZone === 'System/Localtime') { |
161
|
|
|
// http://trac.agavi.org/ticket/1008 |
162
|
|
|
throw new AgaviException("Your default timezone is 'System/Localtime', which likely means that you're running Debian, Ubuntu or some other Linux distribution that chose to include a useless and broken patch for system timezone database lookups into their PHP package, despite this very change being declined by the PHP development team for inclusion into PHP itself.\nThis pseudo-timezone, which is not defined in the standard 'tz' database used across many operating systems and applications, works for internal PHP classes and functions because the 'real' system timezone is resolved instead, but there is no way for an application to obtain the actual timezone name that 'System/Localtime' resolves to internally - information Agavi needs to perform accurate calculations and operations on dates and times.\n\nPlease set a correct timezone name (e.g. Europe/London) via 'date.timezone' in php.ini, use date_default_timezone_set() to set it in your code, or define a default timezone for Agavi to use in translation.xml. If you have some minutes to spare, file a bug report with your operating system vendor about this problem.\n\nIf you'd like to learn more about this issue, please refer to http://trac.agavi.org/ticket/1008"); |
163
|
|
|
} |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* Do any necessary startup work after initialization. |
168
|
|
|
* |
169
|
|
|
* This method is not called directly after initialize(). |
170
|
|
|
* |
171
|
|
|
* @author David Zülke <[email protected]> |
172
|
|
|
* @since 0.11.0 |
173
|
|
|
*/ |
174
|
|
|
public function startup() |
175
|
|
|
{ |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* Execute the shutdown procedure. |
180
|
|
|
* |
181
|
|
|
* @author David Zülke <[email protected]> |
182
|
|
|
* @since 0.11.0 |
183
|
|
|
*/ |
184
|
|
|
public function shutdown() |
185
|
|
|
{ |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Retrieve the current application context. |
190
|
|
|
* |
191
|
|
|
* @return Context The current Context instance. |
192
|
|
|
* |
193
|
|
|
* @author Dominik del Bondio <[email protected]> |
194
|
|
|
* @since 0.11.0 |
195
|
|
|
*/ |
196
|
|
|
final public function getContext() |
197
|
|
|
{ |
198
|
|
|
return $this->context; |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* Returns the list of available locales. |
203
|
|
|
* |
204
|
|
|
* @author David Zülke <[email protected]> |
205
|
|
|
* @since 0.11.0 |
206
|
|
|
*/ |
207
|
|
|
public function getAvailableLocales() |
208
|
|
|
{ |
209
|
|
|
return $this->availableLocales; |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
/** |
213
|
|
|
* Sets the current locale. |
214
|
|
|
* |
215
|
|
|
* @param string $identifier The locale identifier. |
216
|
|
|
* |
217
|
|
|
* @author Dominik del Bondio <[email protected]> |
218
|
|
|
* @since 0.11.0 |
219
|
|
|
*/ |
220
|
|
|
public function setLocale($identifier) |
221
|
|
|
{ |
222
|
|
|
$this->currentLocaleIdentifier = $this->getLocaleIdentifier($identifier); |
223
|
|
|
$givenData = Locale::parseLocaleIdentifier($identifier); |
224
|
|
|
$actualData = Locale::parseLocaleIdentifier($this->currentLocaleIdentifier); |
225
|
|
|
// construct the given name from the locale from the closest match and the options that were given to the requested locale identifier |
226
|
|
|
$this->givenLocaleIdentifier = $actualData['locale_str'] . $givenData['option_str']; |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* Retrieve the current locale. |
231
|
|
|
* |
232
|
|
|
* @return Locale The current locale. |
233
|
|
|
* |
234
|
|
|
* @author Dominik del Bondio <[email protected]> |
235
|
|
|
* @since 0.11.0 |
236
|
|
|
*/ |
237
|
|
|
public function getCurrentLocale() |
238
|
|
|
{ |
239
|
|
|
$this->loadCurrentLocale(); |
240
|
|
|
return $this->currentLocale; |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Retrieve the current locale identifier. This may not necessarily match |
245
|
|
|
* what has be given to setLocale() but instead the identifier of the closest |
246
|
|
|
* match from the available locales. |
247
|
|
|
* |
248
|
|
|
* @return string The locale identifier. |
249
|
|
|
* |
250
|
|
|
* @author Dominik del Bondio <[email protected]> |
251
|
|
|
* @since 0.11.0 |
252
|
|
|
*/ |
253
|
|
|
public function getCurrentLocaleIdentifier() |
254
|
|
|
{ |
255
|
|
|
return $this->currentLocaleIdentifier; |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
/** |
259
|
|
|
* Retrieve the default locale. |
260
|
|
|
* |
261
|
|
|
* @return Locale The current default. |
262
|
|
|
* |
263
|
|
|
* @author David Zülke <[email protected]> |
264
|
|
|
* @since 0.11.0 |
265
|
|
|
*/ |
266
|
|
|
public function getDefaultLocale() |
267
|
|
|
{ |
268
|
|
|
return $this->getLocale($this->getDefaultLocaleIdentifier()); |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
/** |
272
|
|
|
* Retrieve the default locale identifier. |
273
|
|
|
* |
274
|
|
|
* @return string The default locale identifier. |
275
|
|
|
* |
276
|
|
|
* @author David Zülke <[email protected]> |
277
|
|
|
* @since 0.11.0 |
278
|
|
|
*/ |
279
|
|
|
public function getDefaultLocaleIdentifier() |
280
|
|
|
{ |
281
|
|
|
return $this->defaultLocaleIdentifier; |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
/** |
285
|
|
|
* Sets the default domain. |
286
|
|
|
* |
287
|
|
|
* @param string $domain The new default domain. |
288
|
|
|
* |
289
|
|
|
* @author Dominik del Bondio <[email protected]> |
290
|
|
|
* @since 0.11.0 |
291
|
|
|
*/ |
292
|
|
|
public function setDefaultDomain($domain) |
293
|
|
|
{ |
294
|
|
|
$this->defaultDomain = $domain; |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
/** |
298
|
|
|
* Retrieve the default domain. |
299
|
|
|
* |
300
|
|
|
* @return string The default domain. |
301
|
|
|
* |
302
|
|
|
* @author Dominik del Bondio <[email protected]> |
303
|
|
|
* @since 0.11.0 |
304
|
|
|
*/ |
305
|
|
|
public function getDefaultDomain() |
306
|
|
|
{ |
307
|
|
|
return $this->defaultDomain; |
308
|
|
|
} |
309
|
|
|
|
310
|
|
|
/** |
311
|
|
|
* Formats a date in the current locale. |
312
|
|
|
* |
313
|
|
|
* @param mixed $date The date to be formatted. |
314
|
|
|
* @param string $domain The domain in which the date should be formatted. |
315
|
|
|
* @param Locale $locale The locale which should be used for formatting. |
316
|
|
|
* Defaults to the currently active locale. |
317
|
|
|
* |
318
|
|
|
* @return string The formatted date. |
319
|
|
|
* |
320
|
|
|
* @author Dominik del Bondio <[email protected]> |
321
|
|
|
* @since 0.11.0 |
322
|
|
|
*/ |
323
|
|
View Code Duplication |
public function _d($date, $domain = null, $locale = null) |
|
|
|
|
324
|
|
|
{ |
325
|
|
|
if ($domain === null) { |
326
|
|
|
$domain = $this->defaultDomain; |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
if ($locale === null) { |
330
|
|
|
$this->loadCurrentLocale(); |
331
|
|
|
} elseif (is_string($locale)) { |
332
|
|
|
$locale = $this->getLocale($locale); |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
$domainExtra = ''; |
336
|
|
|
$translator = $this->getTranslators($domain, $domainExtra, self::DATETIME); |
337
|
|
|
|
338
|
|
|
$retval = $translator->translate($date, $domainExtra, $locale); |
339
|
|
|
|
340
|
|
|
$retval = $this->applyFilters($retval, $domain, self::DATETIME); |
341
|
|
|
|
342
|
|
|
return $retval; |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
/** |
346
|
|
|
* Formats a currency amount in the current locale. |
347
|
|
|
* |
348
|
|
|
* @param mixed $number The number to be formatted. |
349
|
|
|
* @param string $domain The domain in which the amount should be formatted. |
350
|
|
|
* @param Locale $locale The locale which should be used for formatting. |
351
|
|
|
* Defaults to the currently active locale. |
352
|
|
|
* |
353
|
|
|
* @return string The formatted number. |
354
|
|
|
* |
355
|
|
|
* @author Dominik del Bondio <[email protected]> |
356
|
|
|
* @since 0.11.0 |
357
|
|
|
*/ |
358
|
|
View Code Duplication |
public function _c($number, $domain = null, $locale = null) |
|
|
|
|
359
|
|
|
{ |
360
|
|
|
if ($domain === null) { |
361
|
|
|
$domain = $this->defaultDomain; |
362
|
|
|
} |
363
|
|
|
|
364
|
|
|
if ($locale === null) { |
365
|
|
|
$this->loadCurrentLocale(); |
366
|
|
|
} elseif (is_string($locale)) { |
367
|
|
|
$locale = $this->getLocale($locale); |
368
|
|
|
} |
369
|
|
|
|
370
|
|
|
$domainExtra = ''; |
371
|
|
|
$translator = $this->getTranslators($domain, $domainExtra, self::CURRENCY); |
372
|
|
|
|
373
|
|
|
$retval = $translator->translate($number, $domainExtra, $locale); |
374
|
|
|
|
375
|
|
|
$retval = $this->applyFilters($retval, $domain, self::CURRENCY); |
376
|
|
|
|
377
|
|
|
return $retval; |
378
|
|
|
} |
379
|
|
|
|
380
|
|
|
/** |
381
|
|
|
* Formats a number in the current locale. |
382
|
|
|
* |
383
|
|
|
* @param mixed $number The number to be formatted. |
384
|
|
|
* @param string $domain The domain in which the number should be formatted. |
385
|
|
|
* @param Locale $locale The locale which should be used for formatting. |
386
|
|
|
* Defaults to the currently active locale. |
387
|
|
|
* |
388
|
|
|
* @return string The formatted number. |
389
|
|
|
* |
390
|
|
|
* @author Dominik del Bondio <[email protected]> |
391
|
|
|
* @since 0.11.0 |
392
|
|
|
*/ |
393
|
|
View Code Duplication |
public function _n($number, $domain = null, $locale = null) |
|
|
|
|
394
|
|
|
{ |
395
|
|
|
if ($domain === null) { |
396
|
|
|
$domain = $this->defaultDomain; |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
if ($locale === null) { |
400
|
|
|
$this->loadCurrentLocale(); |
401
|
|
|
} elseif (is_string($locale)) { |
402
|
|
|
$locale = $this->getLocale($locale); |
403
|
|
|
} |
404
|
|
|
|
405
|
|
|
$domainExtra = ''; |
406
|
|
|
$translator = $this->getTranslators($domain, $domainExtra, self::NUMBER); |
407
|
|
|
|
408
|
|
|
$retval = $translator->translate($number, $domainExtra, $locale); |
409
|
|
|
|
410
|
|
|
$retval = $this->applyFilters($retval, $domain, self::NUMBER); |
411
|
|
|
|
412
|
|
|
return $retval; |
413
|
|
|
} |
414
|
|
|
|
415
|
|
|
/** |
416
|
|
|
* Translate a message into the current locale. |
417
|
|
|
* |
418
|
|
|
* @param mixed $message The message. |
419
|
|
|
* @param string $domain The domain in which the translation should be done. |
420
|
|
|
* @param Locale $locale The locale which should be used for formatting. |
421
|
|
|
* Defaults to the currently active locale. |
422
|
|
|
* @param array $parameters The parameters which should be used for sprintf on |
423
|
|
|
* the translated string. |
424
|
|
|
* |
425
|
|
|
* @return string The translated message. |
426
|
|
|
* |
427
|
|
|
* @author Dominik del Bondio <[email protected]> |
428
|
|
|
* @since 0.11.0 |
429
|
|
|
*/ |
430
|
|
|
public function _($message, $domain = null, $locale = null, array $parameters = null) |
431
|
|
|
{ |
432
|
|
|
if ($domain === null) { |
433
|
|
|
$domain = $this->defaultDomain; |
434
|
|
|
} |
435
|
|
|
|
436
|
|
|
if ($locale === null) { |
437
|
|
|
$this->loadCurrentLocale(); |
438
|
|
|
} elseif (is_string($locale)) { |
439
|
|
|
$locale = $this->getLocale($locale); |
440
|
|
|
} |
441
|
|
|
|
442
|
|
|
$domainExtra = ''; |
443
|
|
|
$translator = $this->getTranslators($domain, $domainExtra, self::MESSAGE); |
444
|
|
|
|
445
|
|
|
$retval = $translator->translate($message, $domainExtra, $locale); |
446
|
|
|
if (is_array($parameters)) { |
447
|
|
|
$retval = vsprintf($retval, $parameters); |
448
|
|
|
} |
449
|
|
|
|
450
|
|
|
$retval = $this->applyFilters($retval, $domain, self::MESSAGE); |
451
|
|
|
|
452
|
|
|
return $retval; |
453
|
|
|
} |
454
|
|
|
|
455
|
|
|
/** |
456
|
|
|
* Translate a singular/plural message into the current locale. |
457
|
|
|
* |
458
|
|
|
* @param string $singularMessage The message for the singular form. |
459
|
|
|
* @param string $pluralMessage The message for the plural form. |
460
|
|
|
* @param int $amount The amount for which the translation should happen. |
461
|
|
|
* @param string $domain The domain in which the translation should be done. |
462
|
|
|
* @param Locale $locale The locale which should be used for formatting. |
463
|
|
|
* Defaults to the currently active locale. |
464
|
|
|
* @param array $parameters The parameters which should be used for sprintf on |
465
|
|
|
* the translated string. |
466
|
|
|
* |
467
|
|
|
* @return string The translated message. |
468
|
|
|
* |
469
|
|
|
* @author David Zülke <[email protected]> |
470
|
|
|
* @since 0.11.0 |
471
|
|
|
*/ |
472
|
|
|
public function __($singularMessage, $pluralMessage, $amount, $domain = null, $locale = null, array $parameters = null) |
473
|
|
|
{ |
474
|
|
|
return $this->_(array($singularMessage, $pluralMessage, $amount), $domain, $locale, $parameters); |
475
|
|
|
} |
476
|
|
|
|
477
|
|
|
/** |
478
|
|
|
* Returns the translators for a given domain. |
479
|
|
|
* |
480
|
|
|
* @param string $domain The domain. |
481
|
|
|
* @param string $domainExtra The remaining part in the domain which didn't match |
482
|
|
|
* @param string $type The type of the translator |
483
|
|
|
* |
484
|
|
|
* @return TranslatorInterface An array of translators for the given domain |
485
|
|
|
* |
486
|
|
|
* @author Dominik del Bondio <[email protected]> |
487
|
|
|
* @since 0.11.0 |
488
|
|
|
*/ |
489
|
|
|
protected function getTranslators(&$domain, &$domainExtra, $type = null) |
490
|
|
|
{ |
491
|
|
|
if ($domain[0] == '.') { |
492
|
|
|
$domain = $this->defaultDomain . $domain; |
493
|
|
|
} |
494
|
|
|
|
495
|
|
|
$domainParts = explode('.', $domain); |
496
|
|
|
|
497
|
|
|
do { |
498
|
|
|
if (count($domainParts) == 0) { |
499
|
|
|
throw new \InvalidArgumentException(sprintf('No translator exists for the domain "%s"', $domain)); |
500
|
|
|
} |
501
|
|
|
$td = implode('.', $domainParts); |
502
|
|
|
array_pop($domainParts); |
503
|
|
|
} while (!isset($this->translators[$td]) || ($type && !isset($this->translators[$td][$type]))); |
|
|
|
|
504
|
|
|
|
505
|
|
|
$domainExtra = substr($domain, strlen($td) + 1); |
506
|
|
|
$domain = $td; |
507
|
|
|
return $type ? $this->translators[$td][$type] : $this->translators[$td]; |
508
|
|
|
} |
509
|
|
|
|
510
|
|
|
/** |
511
|
|
|
* Returns the translators for a given domain and type. The domain can contain |
512
|
|
|
* any extra parts which will be ignored. Will return null when no translator |
513
|
|
|
* is defined. |
514
|
|
|
* |
515
|
|
|
* @param string $domain The domain. |
516
|
|
|
* @param string $type The type of the translator. |
517
|
|
|
* |
518
|
|
|
* @return TranslatorInterface The translator instance. |
519
|
|
|
* |
520
|
|
|
* @author Dominik del Bondio <[email protected]> |
521
|
|
|
* @since 0.11.0 |
522
|
|
|
*/ |
523
|
|
|
public function getDomainTranslator($domain, $type) |
524
|
|
|
{ |
525
|
|
|
try { |
526
|
|
|
$domainExtra = ''; |
527
|
|
|
return $this->getTranslators($domain, $domainExtra, $type); |
528
|
|
|
} catch (\InvalidArgumentException $e) { |
529
|
|
|
return null; |
530
|
|
|
} |
531
|
|
|
} |
532
|
|
|
|
533
|
|
|
/** |
534
|
|
|
* Returns the translator filters for a given domain. |
535
|
|
|
* |
536
|
|
|
* @param string $message The message. |
537
|
|
|
* @param string $domain The domain (w/o extra parts). |
538
|
|
|
* @param string $type The type. |
539
|
|
|
* |
540
|
|
|
* @return string The new message. |
541
|
|
|
* |
542
|
|
|
* @author David Zülke <[email protected]> |
543
|
|
|
* @since 0.11.0 |
544
|
|
|
*/ |
545
|
|
|
protected function applyFilters($message, $domain, $type = self::MESSAGE) |
546
|
|
|
{ |
547
|
|
|
if (isset($this->translatorFilters[$domain][$type])) { |
548
|
|
|
foreach ($this->translatorFilters[$domain][$type] as $filter) { |
|
|
|
|
549
|
|
|
$message = call_user_func($filter, $message); |
550
|
|
|
} |
551
|
|
|
} |
552
|
|
|
|
553
|
|
|
return $message; |
554
|
|
|
} |
555
|
|
|
|
556
|
|
|
/** |
557
|
|
|
* Loads the available locales into the instance variable |
558
|
|
|
* |
559
|
|
|
* @author Dominik del Bondio <[email protected]> |
560
|
|
|
* @since 0.11.0 |
561
|
|
|
*/ |
562
|
|
|
protected function loadAvailableLocales() |
563
|
|
|
{ |
564
|
|
|
$this->availableLocales = $this->availableConfigLocales; |
565
|
|
|
} |
566
|
|
|
|
567
|
|
|
/** |
568
|
|
|
* Lazy loads the current locale if necessary. |
569
|
|
|
* |
570
|
|
|
* @author Dominik del Bondio <[email protected]> |
571
|
|
|
* @since 0.11.0 |
572
|
|
|
*/ |
573
|
|
|
protected function loadCurrentLocale() |
574
|
|
|
{ |
575
|
|
|
if (!$this->currentLocale || $this->currentLocale->getIdentifier() != $this->givenLocaleIdentifier) { |
576
|
|
|
$this->currentLocale = $this->getLocale($this->givenLocaleIdentifier); |
577
|
|
|
// we first need to initialize all message translators before the number formatters |
578
|
|
View Code Duplication |
foreach ($this->translators as $translatorList) { |
|
|
|
|
579
|
|
|
/** |
580
|
|
|
* @var string $type |
581
|
|
|
* @var TranslatorInterface $translator |
582
|
|
|
*/ |
583
|
|
|
foreach ($translatorList as $type => $translator) { |
584
|
|
|
if ($type == self::MESSAGE) { |
585
|
|
|
$translator->localeChanged($this->currentLocale); |
586
|
|
|
} |
587
|
|
|
} |
588
|
|
|
} |
589
|
|
View Code Duplication |
foreach ($this->translators as $translatorList) { |
|
|
|
|
590
|
|
|
foreach ($translatorList as $type => $translator) { |
591
|
|
|
if ($type != self::MESSAGE) { |
592
|
|
|
$translator->localeChanged($this->currentLocale); |
593
|
|
|
} |
594
|
|
|
} |
595
|
|
|
} |
596
|
|
|
} |
597
|
|
|
} |
598
|
|
|
|
599
|
|
|
/** |
600
|
|
|
* Loads the supplemental data into the instance variable |
601
|
|
|
* |
602
|
|
|
* @author Dominik del Bondio <[email protected]> |
603
|
|
|
* @since 0.11.0 |
604
|
|
|
*/ |
605
|
|
|
protected function loadSupplementalData() |
606
|
|
|
{ |
607
|
|
|
$this->supplementalData = include(ConfigCache::checkConfig(Config::get('core.cldr_dir') . '/supplementalData.xml')); |
608
|
|
|
} |
609
|
|
|
|
610
|
|
|
/** |
611
|
|
|
* Loads the time zone data. |
612
|
|
|
* |
613
|
|
|
* @author Dominik del Bondio <[email protected]> |
614
|
|
|
* @since 0.11.0 |
615
|
|
|
*/ |
616
|
|
|
protected function loadTimeZoneData() |
617
|
|
|
{ |
618
|
|
|
$this->timeZoneList = include(Config::get('core.cldr_dir') . '/timezones/zonelist.php'); |
619
|
|
|
} |
620
|
|
|
|
621
|
|
|
/** |
622
|
|
|
* Returns all the identifiers of the available locales which match the given |
623
|
|
|
* locale identifier. |
624
|
|
|
* |
625
|
|
|
* @param string $identifier A locale identifier |
626
|
|
|
* |
627
|
|
|
* @return array The actual locale identifiers of the available locales. |
628
|
|
|
* |
629
|
|
|
* @author Dominik del Bondio <[email protected]> |
630
|
|
|
* @author David Zülke <[email protected]> |
631
|
|
|
* @author Thomas Bachem <[email protected]> |
632
|
|
|
*/ |
633
|
|
|
public function getMatchingLocaleIdentifiers($identifier) |
634
|
|
|
{ |
635
|
|
|
// if a locale with the given identifier doesn't exist try to find the closest matches |
636
|
|
|
if (isset($this->availableLocales[$identifier])) { |
637
|
|
|
return array($identifier); |
638
|
|
|
} |
639
|
|
|
|
640
|
|
|
$idData = Locale::parseLocaleIdentifier($identifier); |
641
|
|
|
|
642
|
|
|
$matchingLocaleIdentifiers = array(); |
643
|
|
|
// iterate over all available locales |
644
|
|
|
foreach ($this->availableLocales as $availableLocaleIdentifier => $availableLocale) { |
645
|
|
|
$matched = false; |
646
|
|
|
// iterate over possible properties to compare against (all given ones must match) |
647
|
|
|
foreach (array('language', 'script', 'territory', 'variant') as $propertyName) { |
648
|
|
|
// only perform check if property was in $identifier |
649
|
|
|
if (isset($idData[$propertyName])) { |
650
|
|
|
// compare against data in locale |
651
|
|
|
if ($idData[$propertyName] == $availableLocale['identifierData'][$propertyName]) { |
652
|
|
|
// fine, continue with next |
653
|
|
|
$matched = true; |
654
|
|
|
} else { |
655
|
|
|
// failed, so we can bail out early and declare as non-matched |
656
|
|
|
$matched = false; |
657
|
|
|
break; |
658
|
|
|
} |
659
|
|
|
} |
660
|
|
|
} |
661
|
|
|
if ($matched) { |
662
|
|
|
$matchingLocaleIdentifiers[] = $availableLocaleIdentifier; |
663
|
|
|
} |
664
|
|
|
} |
665
|
|
|
|
666
|
|
|
return $matchingLocaleIdentifiers; |
667
|
|
|
} |
668
|
|
|
|
669
|
|
|
/** |
670
|
|
|
* Returns the identifier of the available locale which matches the given |
671
|
|
|
* locale identifier most. |
672
|
|
|
* |
673
|
|
|
* @param string $identifier A locale identifier |
674
|
|
|
* |
675
|
|
|
* @return string The actual locale identifier of the available locale. |
676
|
|
|
* |
677
|
|
|
* @author Dominik del Bondio <[email protected]> |
678
|
|
|
* @author David Zülke <[email protected]> |
679
|
|
|
* @since 0.11.0 |
680
|
|
|
*/ |
681
|
|
|
public function getLocaleIdentifier($identifier) |
682
|
|
|
{ |
683
|
|
|
if (isset($this->localeIdentifierCache[$identifier])) { |
684
|
|
|
return $this->localeIdentifierCache[$identifier]; |
685
|
|
|
} |
686
|
|
|
|
687
|
|
|
$matchingLocaleIdentifiers = $this->getMatchingLocaleIdentifiers($identifier); |
688
|
|
|
|
689
|
|
|
switch (count($matchingLocaleIdentifiers)) { |
690
|
|
|
case 1: |
691
|
|
|
$availableLocaleIdentifier = current($matchingLocaleIdentifiers); |
692
|
|
|
break; |
693
|
|
|
case 0: |
694
|
|
|
throw new AgaviException('Specified locale identifier ' . $identifier . ' which has no matching available locale defined'); |
695
|
|
|
default: |
696
|
|
|
throw new AgaviException('Specified ambiguous locale identifier ' . $identifier . ' which has matches: ' . implode(', ', $matchingLocaleIdentifiers)); |
697
|
|
|
} |
698
|
|
|
|
699
|
|
|
return $this->localeIdentifierCache[$identifier] = $availableLocaleIdentifier; |
700
|
|
|
} |
701
|
|
|
|
702
|
|
|
/** |
703
|
|
|
* Returns a new AgaviLocale object from the given identifier. |
704
|
|
|
* |
705
|
|
|
* @param string $identifier The locale identifier |
706
|
|
|
* @param bool $forceNew Force a new instance even if an identical one exists. |
707
|
|
|
* |
708
|
|
|
* @return Locale The locale instance which matches the available |
709
|
|
|
* locales most. |
710
|
|
|
* |
711
|
|
|
* @author Dominik del Bondio <[email protected]> |
712
|
|
|
* @author David Zülke <[email protected]> |
713
|
|
|
* @since 0.11.0 |
714
|
|
|
*/ |
715
|
|
|
public function getLocale($identifier, $forceNew = false) |
716
|
|
|
{ |
717
|
|
|
// enable shortcut notation to only set options to the current locale |
718
|
|
|
if ($identifier[0] == '@' && $this->currentLocaleIdentifier) { |
719
|
|
|
$idData = Locale::parseLocaleIdentifier($this->currentLocaleIdentifier); |
720
|
|
|
$identifier = $idData['locale_str'] . $identifier; |
721
|
|
|
|
722
|
|
|
$newIdData = Locale::parseLocaleIdentifier($identifier); |
723
|
|
|
$idData['options'] = array_merge($idData['options'], $newIdData['options']); |
724
|
|
|
} else { |
725
|
|
|
$idData = Locale::parseLocaleIdentifier($identifier); |
726
|
|
|
} |
727
|
|
|
// this doesn't care about the options |
728
|
|
|
$availableLocale = $this->availableLocales[$this->getLocaleIdentifier($identifier)]; |
729
|
|
|
|
730
|
|
|
// if the user wants all options reset he supplies an 'empty' option set (identifier ends with @) |
731
|
|
|
if (substr($identifier, -1) == '@') { |
732
|
|
|
$idData['options'] = array(); |
733
|
|
|
} else { |
734
|
|
|
$idData['options'] = array_merge($availableLocale['identifierData']['options'], $idData['options']); |
735
|
|
|
} |
736
|
|
|
|
737
|
|
|
if (($atPos = strpos($identifier, '@')) !== false) { |
738
|
|
|
$identifier = $availableLocale['identifierData']['locale_str'] . substr($identifier, $atPos); |
739
|
|
|
} else { |
740
|
|
|
$identifier = $availableLocale['identifier']; |
741
|
|
|
} |
742
|
|
|
|
743
|
|
|
if (!$forceNew && isset($this->localeCache[$identifier])) { |
744
|
|
|
return $this->localeCache[$identifier]; |
745
|
|
|
} |
746
|
|
|
|
747
|
|
|
if (!isset($this->localeDataCache[$idData['locale_str']])) { |
748
|
|
|
$lookupPath = Locale::getLookupPath($availableLocale['identifierData']); |
749
|
|
|
$cldrDir = Config::get('core.cldr_dir'); |
750
|
|
|
$data = null; |
751
|
|
|
|
752
|
|
|
foreach ($lookupPath as $localeName) { |
753
|
|
|
$fileName = $cldrDir . '/locales/' . $localeName . '.xml'; |
754
|
|
|
if (is_readable($fileName)) { |
755
|
|
|
$data = include(ConfigCache::checkConfig($fileName)); |
756
|
|
|
break; |
757
|
|
|
} |
758
|
|
|
} |
759
|
|
|
if ($data === null) { |
760
|
|
|
throw new AgaviException('No data available for locale ' . $identifier); |
761
|
|
|
} |
762
|
|
|
|
763
|
|
|
if ($availableLocale['identifierData']['territory']) { |
764
|
|
|
$territory = $availableLocale['identifierData']['territory']; |
765
|
|
|
if (isset($this->supplementalData['territories'][$territory]['currencies'])) { |
766
|
|
|
$slice = array_slice($this->supplementalData['territories'][$territory]['currencies'], 0, 1); |
767
|
|
|
$currency = current($slice); |
768
|
|
|
$data['locale']['currency'] = $currency['currency']; |
769
|
|
|
} |
770
|
|
|
} |
771
|
|
|
|
772
|
|
|
$this->localeDataCache[$idData['locale_str']] = $data; |
773
|
|
|
} |
774
|
|
|
|
775
|
|
|
$data = $this->localeDataCache[$idData['locale_str']]; |
776
|
|
|
|
777
|
|
View Code Duplication |
if (isset($idData['options']['calendar'])) { |
|
|
|
|
778
|
|
|
$data['locale']['calendar'] = $idData['options']['calendar']; |
779
|
|
|
} |
780
|
|
|
|
781
|
|
View Code Duplication |
if (isset($idData['options']['currency'])) { |
|
|
|
|
782
|
|
|
$data['locale']['currency'] = $idData['options']['currency']; |
783
|
|
|
} |
784
|
|
|
|
785
|
|
View Code Duplication |
if (isset($idData['options']['timezone'])) { |
|
|
|
|
786
|
|
|
$data['locale']['timezone'] = $idData['options']['timezone']; |
787
|
|
|
} |
788
|
|
|
|
789
|
|
|
$locale = new Locale(); |
790
|
|
|
$locale->initialize($this->context, $availableLocale['parameters'], $identifier, $data); |
791
|
|
|
|
792
|
|
|
if (!$forceNew) { |
793
|
|
|
$this->localeCache[$identifier] = $locale; |
794
|
|
|
} |
795
|
|
|
|
796
|
|
|
return $locale; |
797
|
|
|
} |
798
|
|
|
|
799
|
|
|
/** |
800
|
|
|
* Sets the default time zone. |
801
|
|
|
* |
802
|
|
|
* @param string $id The timezone identifier |
803
|
|
|
* |
804
|
|
|
* @author Dominik del Bondio <[email protected]> |
805
|
|
|
* @since 0.11.0 |
806
|
|
|
*/ |
807
|
|
|
public function setDefaultTimeZone($id) |
808
|
|
|
{ |
809
|
|
|
$this->defaultTimeZone = $id; |
810
|
|
|
} |
811
|
|
|
|
812
|
|
|
/** |
813
|
|
|
* Gets the instance of the current timezone. |
814
|
|
|
* |
815
|
|
|
* @return TimeZone The current timezone instance. |
816
|
|
|
* |
817
|
|
|
* @author Dominik del Bondio <[email protected]> |
818
|
|
|
* @since 0.11.0 |
819
|
|
|
* |
820
|
|
|
* @deprecated Superseded by TranslationManager::getDefaultTimeZone() |
821
|
|
|
*/ |
822
|
|
|
public function getCurrentTimeZone() |
823
|
|
|
{ |
824
|
|
|
return $this->getDefaultTimeZone(); |
825
|
|
|
} |
826
|
|
|
|
827
|
|
|
/** |
828
|
|
|
* Get the default timezone instance. |
829
|
|
|
* |
830
|
|
|
* @return TimeZone The default timezone instance. |
831
|
|
|
* |
832
|
|
|
* @author David Zülke <[email protected]> |
833
|
|
|
* @since 1.0.0 |
834
|
|
|
*/ |
835
|
|
|
public function getDefaultTimeZone() |
836
|
|
|
{ |
837
|
|
|
return $this->createTimeZone($this->defaultTimeZone); |
838
|
|
|
} |
839
|
|
|
|
840
|
|
|
/** |
841
|
|
|
* Gets the territory id a (resolved) timezone id belongs to. |
842
|
|
|
* |
843
|
|
|
* @param string $id The resolved timezone id. |
844
|
|
|
* @param bool $hasMultipleZones Will receive whether the territory has multiple |
845
|
|
|
* time zones |
846
|
|
|
* |
847
|
|
|
* @return string The territory identifier or null. |
848
|
|
|
* |
849
|
|
|
* @author Dominik del Bondio <[email protected]> |
850
|
|
|
* @since 0.11.0 |
851
|
|
|
*/ |
852
|
|
|
public function getTimeZoneTerritory($id, &$hasMultipleZones = false) |
853
|
|
|
{ |
854
|
|
|
if (isset($this->supplementalData['timezones']['territories'][$id])) { |
855
|
|
|
$territory = $this->supplementalData['timezones']['territories'][$id]; |
856
|
|
|
$hasMultipleZones = isset($this->supplementalData['timezones']['multiZones'][$territory]); |
857
|
|
|
return $territory; |
858
|
|
|
} |
859
|
|
|
|
860
|
|
|
return null; |
861
|
|
|
} |
862
|
|
|
|
863
|
|
|
/** |
864
|
|
|
* Resolved the given timezone identifier to its 'real' timezone id. |
865
|
|
|
* |
866
|
|
|
* This provides the same functionality like |
867
|
|
|
* $tm->createTimeZone(id)->getResolvedId() with the difference, that using |
868
|
|
|
* this method will not create a new timezone instance and look up the |
869
|
|
|
* resolved id there, but instead directly returns the resolved id by using |
870
|
|
|
* a simple lookup. |
871
|
|
|
* |
872
|
|
|
* @param int $id The timezone id to be resolved |
873
|
|
|
* @return int The resolved timezone id |
874
|
|
|
* |
875
|
|
|
* @author Dominik del Bondio <[email protected]> |
876
|
|
|
* @since 1.0.0 |
877
|
|
|
*/ |
878
|
|
|
public function resolveTimeZoneId($id) |
879
|
|
|
{ |
880
|
|
|
if (isset($this->timeZoneList[$id])) { |
881
|
|
View Code Duplication |
while ($this->timeZoneList[$id]['type'] == 'link') { |
|
|
|
|
882
|
|
|
$id = $this->timeZoneList[$id]['to']; |
883
|
|
|
} |
884
|
|
|
} |
885
|
|
|
|
886
|
|
|
return $id; |
887
|
|
|
} |
888
|
|
|
|
889
|
|
|
|
890
|
|
|
/** |
891
|
|
|
* Creates a new timezone instance for the given identifier. |
892
|
|
|
* |
893
|
|
|
* Please note that this method caches the results for each identifier, so |
894
|
|
|
* if you plan to modify the timezones returned by this method you need to |
895
|
|
|
* clone them first. Alternatively you can set the cache parameter to false, |
896
|
|
|
* but this will mean the data for this timezone will be loaded from the |
897
|
|
|
* hdd again. |
898
|
|
|
* |
899
|
|
|
* @return TimeZone The timezone instance for the given id. |
900
|
|
|
* |
901
|
|
|
* @author Dominik del Bondio <[email protected]> |
902
|
|
|
* @since 0.11.0 |
903
|
|
|
*/ |
904
|
|
|
public function createTimeZone($id, $cache = true) |
905
|
|
|
{ |
906
|
|
|
if (!isset($this->timeZoneList[$id])) { |
907
|
|
|
try { |
908
|
|
|
return TimeZone::createCustomTimeZone($this, $id); |
909
|
|
|
} catch (\Exception $e) { |
910
|
|
|
return null; |
911
|
|
|
} |
912
|
|
|
} |
913
|
|
|
|
914
|
|
|
if (!isset($this->timeZoneCache[$id]) || !$cache) { |
915
|
|
|
$currId = $id; |
916
|
|
|
|
917
|
|
|
// resolve links |
918
|
|
View Code Duplication |
while ($this->timeZoneList[$currId]['type'] == 'link') { |
|
|
|
|
919
|
|
|
$currId = $this->timeZoneList[$currId]['to']; |
920
|
|
|
} |
921
|
|
|
|
922
|
|
|
$zoneData = include(Config::get('core.cldr_dir') . '/timezones/' . $this->timeZoneList[$currId]['filename']); |
923
|
|
|
|
924
|
|
|
$zone = new OlsonTimeZone($this, $id, $zoneData); |
925
|
|
|
$zone->setResolvedId($currId); |
926
|
|
|
if ($cache) { |
927
|
|
|
$this->timeZoneCache[$id] = $zone; |
928
|
|
|
} |
929
|
|
|
} else { |
930
|
|
|
$zone = $this->timeZoneCache[$id]; |
931
|
|
|
} |
932
|
|
|
|
933
|
|
|
return $zone; |
934
|
|
|
} |
935
|
|
|
|
936
|
|
|
/** |
937
|
|
|
* Creates a new calendar instance with the current time set. |
938
|
|
|
* |
939
|
|
|
* @param mixed $type This can be either a Locale, a TimeZone or |
940
|
|
|
* a string specifying the calendar type. |
941
|
|
|
* |
942
|
|
|
* @return Calendar The current timezone instance. |
943
|
|
|
* |
944
|
|
|
* @author Dominik del Bondio <[email protected]> |
945
|
|
|
* @since 0.11.0 |
946
|
|
|
*/ |
947
|
|
|
public function createCalendar($type = null) |
948
|
|
|
{ |
949
|
|
|
$locale = $this->getCurrentLocale(); |
950
|
|
|
$calendarType = null; |
951
|
|
|
$zone = null; |
952
|
|
|
$time = null; |
953
|
|
|
if ($type instanceof Locale) { |
954
|
|
|
$locale = $type; |
955
|
|
|
} elseif ($type instanceof TimeZone) { |
956
|
|
|
$zone = $type; |
957
|
|
|
} elseif ($type instanceof \DateTime) { |
958
|
|
|
$time = $type; |
959
|
|
|
} elseif (is_int($type)) { |
960
|
|
|
$time = $type * DateDefinitions::MILLIS_PER_SECOND; |
961
|
|
|
} elseif ($type !== null) { |
962
|
|
|
$calendarType = $type; |
963
|
|
|
} |
964
|
|
|
if ($time === null) { |
965
|
|
|
$time = Calendar::getNow(); |
966
|
|
|
} |
967
|
|
|
|
968
|
|
|
if (!$zone) { |
969
|
|
|
if ($locale->getLocaleTimeZone()) { |
970
|
|
|
$zone = $this->createTimeZone($locale->getLocaleTimeZone()); |
971
|
|
|
} |
972
|
|
|
} |
973
|
|
|
|
974
|
|
|
if (!$calendarType) { |
975
|
|
|
$calendarType = $locale->getLocaleCalendar(); |
976
|
|
|
if (!$calendarType) { |
977
|
|
|
$calendarType = Calendar::GREGORIAN; |
978
|
|
|
} |
979
|
|
|
} |
980
|
|
|
|
981
|
|
|
switch ($calendarType) { |
982
|
|
|
case Calendar::GREGORIAN: |
983
|
|
|
$c = new GregorianCalendar($this /* $locale */); |
984
|
|
|
break; |
985
|
|
|
default: |
986
|
|
|
throw new AgaviException('Calendar type ' . $calendarType . ' not supported'); |
987
|
|
|
} |
988
|
|
|
|
989
|
|
|
// Now, reset calendar to default state: |
990
|
|
|
if ($zone) { |
991
|
|
|
$c->setTimeZone($zone); |
992
|
|
|
} |
993
|
|
|
|
994
|
|
|
if ($time instanceof \DateTime) { |
995
|
|
|
// FIXME: we can't use $time->getTimezone()->getName() here since that triggers |
996
|
|
|
// https://github.com/facebook/hhvm/issues/1777 but luckily using format('e') |
997
|
|
|
// works for both php and hhvm |
998
|
|
|
$tzName = $time->format('e'); |
999
|
|
|
|
1000
|
|
|
if (preg_match('/^[+-0-9]/', $tzName)) { |
1001
|
|
|
$tzName = 'GMT' . $tzName; |
1002
|
|
|
} |
1003
|
|
|
$c->setTimeZone($this->createTimeZone($tzName)); |
1004
|
|
|
$dateStr = $time->format('Y z G i s'); |
1005
|
|
|
list($year, $doy, $hour, $minute, $second) = explode(' ', $dateStr); |
1006
|
|
|
$c->set(DateDefinitions::YEAR, $year); |
1007
|
|
|
$c->set(DateDefinitions::DAY_OF_YEAR, $doy + 1); |
1008
|
|
|
$c->set(DateDefinitions::HOUR_OF_DAY, $hour); |
1009
|
|
|
$c->set(DateDefinitions::MINUTE, $minute); |
1010
|
|
|
$c->set(DateDefinitions::SECOND, $second); |
1011
|
|
|
|
1012
|
|
|
// complete the calendar |
1013
|
|
|
$c->getAll(); |
1014
|
|
|
} else { |
1015
|
|
|
$c->setTime($time); // let the new calendar have the current time. |
1016
|
|
|
} |
1017
|
|
|
|
1018
|
|
|
return $c; |
1019
|
|
|
} |
1020
|
|
|
|
1021
|
|
|
/** |
1022
|
|
|
* Creates a new date format instance with the given format. |
1023
|
|
|
* |
1024
|
|
|
* @param string $format The date format. |
1025
|
|
|
* |
1026
|
|
|
* @return DateFormat The dateformat instance. |
1027
|
|
|
* |
1028
|
|
|
* @author Dominik del Bondio <[email protected]> |
1029
|
|
|
* @since 0.11.0 |
1030
|
|
|
*/ |
1031
|
|
|
public function createDateFormat($format) |
1032
|
|
|
{ |
1033
|
|
|
$dateFormat = new DateFormat($format); |
1034
|
|
|
$dateFormat->initialize($this->getContext()); |
1035
|
|
|
return $dateFormat; |
1036
|
|
|
} |
1037
|
|
|
|
1038
|
|
|
|
1039
|
|
|
/** |
1040
|
|
|
* Returns the stored information from the ldml supplemental data about a |
1041
|
|
|
* territory. |
1042
|
|
|
* |
1043
|
|
|
* @param string $country The uppercase 2 letter country iso code. |
1044
|
|
|
* |
1045
|
|
|
* @return array The data. |
1046
|
|
|
* |
1047
|
|
|
* @author Dominik del Bondio <[email protected]> |
1048
|
|
|
* @since 0.11.0 |
1049
|
|
|
*/ |
1050
|
|
|
public function getTerritoryData($country) |
1051
|
|
|
{ |
1052
|
|
|
if (!isset($this->supplementalData['territories'][$country])) { |
1053
|
|
|
return array(); |
1054
|
|
|
} |
1055
|
|
|
return $this->supplementalData['territories'][$country]; |
1056
|
|
|
} |
1057
|
|
|
|
1058
|
|
|
/** |
1059
|
|
|
* Returns an array containing digits and rounding information for a currency. |
1060
|
|
|
* |
1061
|
|
|
* @param string $currency The uppercase 3 letter currency iso code. |
1062
|
|
|
* |
1063
|
|
|
* @return array The data. |
1064
|
|
|
* |
1065
|
|
|
* @author Dominik del Bondio <[email protected]> |
1066
|
|
|
* @since 0.11.0 |
1067
|
|
|
*/ |
1068
|
|
|
public function getCurrencyFraction($currency) |
1069
|
|
|
{ |
1070
|
|
|
if (!isset($this->supplementalData['fractions'][$currency])) { |
1071
|
|
|
return $this->supplementalData['fractions']['DEFAULT']; |
1072
|
|
|
} |
1073
|
|
|
return $this->supplementalData['fractions'][$currency]; |
1074
|
|
|
} |
1075
|
|
|
} |
1076
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.