PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.3.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.3.0
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Translation / Translator.php
matomo / app / core / Translation Last commit date
Loader 5 years ago Transifex 5 years ago Translator.php 5 years ago
Translator.php
282 lines
1 <?php
2 /**
3 * Matomo - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 */
8
9 namespace Piwik\Translation;
10
11 use Piwik\Config;
12 use Piwik\Piwik;
13 use Piwik\Translation\Loader\LoaderInterface;
14
15 /**
16 * Translates messages.
17 *
18 * @api
19 */
20 class Translator
21 {
22 /**
23 * Contains the translated messages, indexed by the language name.
24 *
25 * @var array
26 */
27 private $translations = array();
28
29 /**
30 * @var string
31 */
32 private $currentLanguage;
33
34 /**
35 * @var string
36 */
37 private $fallback = 'en';
38
39 /**
40 * Directories containing the translations to load.
41 *
42 * @var string[]
43 */
44 private $directories = array();
45
46 /**
47 * @var LoaderInterface
48 */
49 private $loader;
50
51 public function __construct(LoaderInterface $loader, array $directories = null)
52 {
53 $this->loader = $loader;
54 $this->currentLanguage = $this->getDefaultLanguage();
55
56 if ($directories === null) {
57 // TODO should be moved out of this class
58 $directories = array(PIWIK_INCLUDE_PATH . '/lang');
59 }
60 $this->directories = $directories;
61 }
62
63 /**
64 * Clean a string that may contain HTML special chars, single/double quotes, HTML entities, leading/trailing whitespace
65 *
66 * @param string $s
67 * @return string
68 */
69 public static function clean($s)
70 {
71 return html_entity_decode(trim($s), ENT_QUOTES, 'UTF-8');
72 }
73
74 /**
75 * Returns an internationalized string using a translation ID. If a translation
76 * cannot be found for the ID, the ID is returned.
77 *
78 * @param string $translationId Translation ID, eg, `General_Date`.
79 * @param array|string|int $args `sprintf` arguments to be applied to the internationalized
80 * string.
81 * @param string|null $language Optionally force the language.
82 * @return string The translated string or `$translationId`.
83 * @api
84 */
85 public function translate($translationId, $args = array(), $language = null)
86 {
87 $args = is_array($args) ? $args : array($args);
88
89 if (strpos($translationId, "_") !== false) {
90 list($plugin, $key) = explode("_", $translationId, 2);
91 $language = is_string($language) ? $language : $this->currentLanguage;
92
93 $translationId = $this->getTranslation($translationId, $language, $plugin, $key);
94 }
95
96 if (count($args) == 0) {
97 return str_replace('%%', '%', $translationId);
98 }
99 return vsprintf($translationId, $args);
100 }
101
102 /**
103 * @return string
104 */
105 public function getCurrentLanguage()
106 {
107 return $this->currentLanguage;
108 }
109
110 /**
111 * @param string $language
112 */
113 public function setCurrentLanguage($language)
114 {
115 if (!$language) {
116 $language = $this->getDefaultLanguage();
117 }
118
119 $this->currentLanguage = $language;
120 }
121
122 /**
123 * @return string The default configured language.
124 */
125 public function getDefaultLanguage()
126 {
127 $generalSection = Config::getInstance()->General;
128
129 // the config may not be available (for example, during environment setup), so we default to 'en'
130 // if the config cannot be found.
131 return @$generalSection['default_language'] ?: 'en';
132 }
133
134 /**
135 * Generate javascript translations array
136 */
137 public function getJavascriptTranslations()
138 {
139 $clientSideTranslations = array();
140 foreach ($this->getClientSideTranslationKeys() as $id) {
141 list($plugin, $key) = explode('_', $id, 2);
142 $clientSideTranslations[$id] = $this->getTranslation($id, $this->currentLanguage, $plugin, $key);
143 }
144
145 $js = 'var translations = ' . json_encode($clientSideTranslations) . ';';
146 $js .= "\n" . 'if (typeof(piwik_translations) == \'undefined\') { var piwik_translations = new Object; }' .
147 'for(var i in translations) { piwik_translations[i] = translations[i];} ';
148 return $js;
149 }
150
151 /**
152 * Returns the list of client side translations by key. These translations will be outputted
153 * to the translation JavaScript.
154 */
155 private function getClientSideTranslationKeys()
156 {
157 $result = array();
158
159 /**
160 * Triggered before generating the JavaScript code that allows i18n strings to be used
161 * in the browser.
162 *
163 * Plugins should subscribe to this event to specify which translations
164 * should be available to JavaScript.
165 *
166 * Event handlers should add whole translation keys, ie, keys that include the plugin name.
167 *
168 * **Example**
169 *
170 * public function getClientSideTranslationKeys(&$result)
171 * {
172 * $result[] = "MyPlugin_MyTranslation";
173 * }
174 *
175 * @param array &$result The whole list of client side translation keys.
176 */
177 Piwik::postEvent('Translate.getClientSideTranslationKeys', array(&$result));
178
179 $result = array_unique($result);
180
181 return $result;
182 }
183
184 /**
185 * Add a directory containing translations.
186 *
187 * @param string $directory
188 */
189 public function addDirectory($directory)
190 {
191 if (isset($this->directories[$directory])) {
192 return;
193 }
194 // index by name to avoid duplicates
195 $this->directories[$directory] = $directory;
196
197 // clear currently loaded translations to force reloading them
198 $this->translations = array();
199 }
200
201 /**
202 * Should be used by tests only, and this method should eventually be removed.
203 */
204 public function reset()
205 {
206 $this->currentLanguage = $this->getDefaultLanguage();
207 $this->directories = array(PIWIK_INCLUDE_PATH . '/lang');
208 $this->translations = array();
209 }
210
211 /**
212 * @param string $translation
213 * @return null|string
214 */
215 public function findTranslationKeyForTranslation($translation)
216 {
217 foreach ($this->getAllTranslations() as $key => $translations) {
218 $possibleKey = array_search($translation, $translations);
219 if (!empty($possibleKey)) {
220 return $key . '_' . $possibleKey;
221 }
222 }
223
224 return null;
225 }
226
227 /**
228 * Returns all the translation messages loaded.
229 *
230 * @return array
231 */
232 public function getAllTranslations()
233 {
234 $this->loadTranslations($this->currentLanguage);
235
236 if (!isset($this->translations[$this->currentLanguage])) {
237 return array();
238 }
239
240 return $this->translations[$this->currentLanguage];
241 }
242
243 private function getTranslation($id, $lang, $plugin, $key)
244 {
245 $this->loadTranslations($lang);
246
247 if (isset($this->translations[$lang][$plugin])
248 && isset($this->translations[$lang][$plugin][$key])
249 ) {
250 return $this->translations[$lang][$plugin][$key];
251 }
252
253 /**
254 * Fallback for keys moved to new Intl plugin to avoid untranslated string in non core plugins
255 * @todo remove this in Piwik 3.0
256 */
257 if ($plugin != 'Intl') {
258 if (isset($this->translations[$lang]['Intl'])
259 && isset($this->translations[$lang]['Intl'][$key])
260 ) {
261 return $this->translations[$lang]['Intl'][$key];
262 }
263 }
264
265 // fallback
266 if ($lang !== $this->fallback) {
267 return $this->getTranslation($id, $this->fallback, $plugin, $key);
268 }
269
270 return $id;
271 }
272
273 private function loadTranslations($language)
274 {
275 if (empty($language) || isset($this->translations[$language])) {
276 return;
277 }
278
279 $this->translations[$language] = $this->loader->load($language, $this->directories);
280 }
281 }
282