Issues (1474)

framework/I18N/TGlobalization.php (1 issue)

1
<?php
2
3
/**
4
 * TGlobalization class file.
5
 *
6
 * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
7
 * @link https://github.com/pradosoft/prado
8
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
9
 */
10
11
namespace Prado\I18N;
12
13
use Prado\Exceptions\TConfigurationException;
14
use Prado\Prado;
15
use Prado\TApplication;
16
use Prado\TPropertyValue;
17
18
/**
19
 * TGlobalization contains settings for Culture, Charset
20
 * and TranslationConfiguration.
21
 *
22
 * TGlobalization can be subclassed to change how the Culture, Charset
23
 * are determined. See TGlobalizationAutoDetect for example of
24
 * setting the Culture based on browser settings.
25
 *
26
 * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
27
 * @since 3.0
28
 */
29
class TGlobalization extends \Prado\TModule
30
{
31
	/**
32
	 * Default character set is 'UTF-8'.
33
	 * @var string
34
	 */
35
	private $_defaultCharset = 'UTF-8';
36
37
	/**
38
	 * Default culture is 'en'.
39
	 * @var string
40
	 */
41
	private $_defaultCulture = 'en';
42
43
	/**
44
	 * The current charset.
45
	 * @var string
46
	 */
47
	private $_charset;
48
49
	/**
50
	 * The current culture.
51
	 * @var string
52
	 */
53
	private $_culture;
54
55
	/**
56
	 * Translation source parameters.
57
	 * @var \Prado\Collections\TMap
58
	 */
59
	private $_translation;
60
61
	/**
62
	 * @var bool whether we should translate the default culture
63
	 */
64
	private $_translateDefaultCulture = true;
65
66
	/**
67
	 * @var bool whether the current culture is Right to Left.
68
	 */
69
	private $_cultureRTL;
70
71
	/**
72
	 * Initialize the Culture and Charset for this application.
73
	 * You should override this method if you want a different way of
74
	 * setting the Culture and/or Charset for your application.
75
	 * If you override this method, call parent::init($xml) first.
76
	 * @param mixed $config application configuration
77
	 */
78
	public function init($config)
79
	{
80
		if ($this->_charset === null) {
81
			$this->_charset = $this->getDefaultCharset();
82
		}
83
		if ($this->_culture === null) {
84
			$this->_culture = $this->getDefaultCulture();
85
		}
86
87
		if ($config !== null) {
88
			if ($this->getApplication()->getConfigurationType() == TApplication::CONFIG_TYPE_PHP) {
89
				$translation = $config['translate'] ?? null;
90
			} else {
91
				$t = $config->getElementByTagName('translation');
92
				$translation = ($t) ? $t->getAttributes() : null;
93
			}
94
			if ($translation) {
95
				$this->setTranslationConfiguration($translation);
96
			}
97
		}
98
		$this->getApplication()->setGlobalization($this);
99
		parent::init($config);
100
	}
101
102
	/**
103
	 * @return string default culture
104
	 */
105
	public function getTranslateDefaultCulture()
106
	{
107
		return $this->_translateDefaultCulture;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->_translateDefaultCulture returns the type boolean which is incompatible with the documented return type string.
Loading history...
108
	}
109
110
	/**
111
	 * @param bool $value default culture, e.g. <tt>en_US</tt> for American English
112
	 */
113
	public function setTranslateDefaultCulture($value)
114
	{
115
		$this->_translateDefaultCulture = TPropertyValue::ensureBoolean($value);
116
	}
117
118
	/**
119
	 * @return string default culture
120
	 */
121
	public function getDefaultCulture()
122
	{
123
		return $this->_defaultCulture;
124
	}
125
126
	/**
127
	 * @param string $culture default culture, e.g. <tt>en_US</tt> for American English
128
	 */
129
	public function setDefaultCulture($culture)
130
	{
131
		$this->_defaultCulture = str_replace('-', '_', $culture);
132
	}
133
134
	/**
135
	 * @return string default charset set
136
	 */
137
	public function getDefaultCharset()
138
	{
139
		return $this->_defaultCharset;
140
	}
141
142
	/**
143
	 * @param string $charset default localization charset, e.g. <tt>UTF-8</tt>
144
	 */
145
	public function setDefaultCharset($charset)
146
	{
147
		$this->_defaultCharset = $charset;
148
	}
149
150
	/**
151
	 * @return string current application culture
152
	 */
153
	public function getCulture()
154
	{
155
		return $this->_culture;
156
	}
157
158
	/**
159
	 * @param string $culture culture, e.g. <tt>en_US</tt> for American English
160
	 */
161
	public function setCulture($culture)
162
	{
163
		if (($culture = str_replace('-', '_', $culture)) != $this->_culture) {
164
			$this->_culture = $culture;
165
			$this->_cultureRTL = null;
166
		}
167
	}
168
169
	/**
170
	 * @return string localization charset
171
	 */
172
	public function getCharset()
173
	{
174
		return $this->_charset;
175
	}
176
177
	/**
178
	 * @param string $charset localization charset, e.g. <tt>UTF-8</tt>
179
	 */
180
	public function setCharset($charset)
181
	{
182
		$this->_charset = $charset;
183
	}
184
185
	/**
186
	 * @return null|\Prado\Collections\TMap translation source configuration.
187
	 */
188
	public function getTranslationConfiguration()
189
	{
190
		return (!$this->_translateDefaultCulture && ($this->getDefaultCulture() == $this->getCulture()))
191
			? null
192
			: $this->_translation;
193
	}
194
195
	/**
196
	 * Sets the translation configuration. Example configuration:
197
	 * ```php
198
	 * $config['type'] = 'XLIFF'; //XLIFF, gettext, PHP or Database
199
	 * $config['source'] = 'Path\to\directory'; // for types XLIFF, PHP and gettext
200
	 * $config['source'] = 'connectionId'; // for type Database
201
	 * $config['catalogue'] = 'messages'; //default catalog
202
	 * $config['autosave'] = 'true'; //save untranslated message
203
	 * $config['cache'] = 'true'; //cache translated message
204
	 * $config['marker'] = '@@'; // surround untranslated text with '@@'
205
	 * ```
206
	 * Throws exception is source is not found.
207
	 * @param array|\Prado\Collections\TMap $config configuration options
208
	 */
209
	protected function setTranslationConfiguration($config)
210
	{
211
		if ($config['type'] == 'XLIFF' || $config['type'] == 'gettext' || $config['type'] == 'PHP') {
212
			if ($config['source']) {
213
				$config['source'] = Prado::getPathOfNamespace($config['source']);
214
				if (!is_dir($config['source'])) {
215
					if (@mkdir($config['source']) === false) {
216
						throw new TConfigurationException(
217
							'globalization_source_path_failed',
218
							$config['source']
219
						);
220
					}
221
					chmod($config['source'], Prado::getDefaultDirPermissions()); //make it deletable
222
				}
223
			} else {
224
				throw new TConfigurationException("invalid source dir '{$config['source']}'");
225
			}
226
		}
227
		if (isset($config['cache']) && TPropertyValue::ensureBoolean($config['cache'])) {
228
			$config['cache'] = $this->getApplication()->getRunTimePath() . '/i18n';
229
			if (!is_dir($config['cache'])) {
230
				if (@mkdir($config['cache']) === false) {
231
					throw new TConfigurationException(
232
						'globalization_cache_path_failed',
233
						$config['cache']
234
					);
235
				}
236
				chmod($config['cache'], Prado::getDefaultDirPermissions()); //make it deletable
237
			}
238
		} else {
239
			unset($config['cache']);
240
		}
241
		$this->_translation = $config;
242
	}
243
244
	/**
245
	 * @return string current translation catalogue.
246
	 */
247
	public function getTranslationCatalogue()
248
	{
249
		return $this->_translation['catalogue'];
250
	}
251
252
	/**
253
	 * @param string $value update the translation catalogue.
254
	 */
255
	public function setTranslationCatalogue($value)
256
	{
257
		$this->_translation['catalogue'] = $value;
258
	}
259
260
	/**
261
	 * Gets all the variants of a specific culture. If the parameter
262
	 * $culture is null, the current culture is used.
263
	 * @param string $culture the Culture string
264
	 * @return array variants of the culture.
265
	 */
266
	public function getCultureVariants($culture = null)
267
	{
268
		if ($culture === null) {
269
			$culture = $this->getCulture();
270
		}
271
		$variants = explode('_', $culture);
272
		$result = [];
273
		for (; count($variants) > 0; array_pop($variants)) {
274
			$result[] = implode('_', $variants);
275
		}
276
		return $result;
277
	}
278
279
	/**
280
	 * Returns a list of possible localized files. Example
281
	 * ```php
282
	 * $files = $app->getLocalizedResource("path/to/Home.page","en_US");
283
	 * ```
284
	 * will return
285
	 * <pre>
286
	 * array
287
	 *   0 => 'path/to/en_US/Home.page'
288
	 *   1 => 'path/to/en/Home.page'
289
	 *   2 => 'path/to/Home.en_US.page'
290
	 *   3 => 'path/to/Home.en.page'
291
	 *   4 => 'path/to/Home.page'
292
	 * </pre>
293
	 * Note that you still need to verify the existance of these files.
294
	 * @param string $file filename
295
	 * @param string $culture culture string, null to use current culture
296
	 * @return array list of possible localized resource files.
297
	 */
298
	public function getLocalizedResource($file, $culture = null)
299
	{
300
		$files = [];
301
		$variants = $this->getCultureVariants($culture);
302
		$path = pathinfo($file);
303
		foreach ($variants as $variant) {
304
			$files[] = $path['dirname'] . DIRECTORY_SEPARATOR . $variant . DIRECTORY_SEPARATOR . $path['basename'];
305
		}
306
		$filename = substr($path['basename'], 0, strrpos($path['basename'], '.'));
307
		foreach ($variants as $variant) {
308
			$files[] = $path['dirname'] . DIRECTORY_SEPARATOR . $filename . '.' . $variant . '.' . $path['extension'];
309
		}
310
		$files[] = $file;
311
		return $files;
312
	}
313
314
	/**
315
	 * This returns whether or not the current culture or the specified
316
	 * culture is right to left orientation.  Default $culture is null, which
317
	 * equal to using $this->Culture as the parameter.
318
	 * @param null|string $culture, default null which makes this grab the current object culture
319
	 * @return bool whether or not the specified or current culture is right to left
320
	 * @since 4.2.0
321
	 */
322
	public function getIsCultureRTL($culture = null)
323
	{
324
		$currentCulture = $this->getCulture();
325
326
		if (($culture === null || $culture == $currentCulture) && $this->_cultureRTL !== null) {
327
			return $this->_cultureRTL;
328
		}
329
		if ($culture === null) {
330
			$culture = $currentCulture;
331
		}
332
		$ci = new \Prado\I18N\core\CultureInfo($culture);
333
		$textDirection = $ci->findInfo('layout/characters');
334
		$isRTL = ($textDirection == 'right-to-left');
335
		if ($culture == $currentCulture) {
336
			$this->_cultureRTL = $isRTL;
337
		}
338
		return $isRTL;
339
	}
340
341
	/**
342
	 * This hard sets the IsCultureRTL property to the value.
343
	 * @param bool $rtl whether or not the culture is right to left
344
	 * @since 4.2.0
345
	 */
346
	public function setIsCultureRTL($rtl)
347
	{
348
		$this->_cultureRTL = TPropertyValue::ensureBoolean($rtl);
349
	}
350
}
351