PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.14.1
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.14.1
5.12.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 Weblate 4 years ago Translator.php 4 years ago
Translator.php
283 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 $translationId = $translationId ?? '';
89
90 if (strpos($translationId, "_") !== false) {
91 list($plugin, $key) = explode("_", $translationId, 2);
92 $language = is_string($language) ? $language : $this->currentLanguage;
93
94 $translationId = $this->getTranslation($translationId, $language, $plugin, $key);
95 }
96
97 if (count($args) == 0) {
98 return str_replace('%%', '%', $translationId);
99 }
100 return vsprintf($translationId, $args);
101 }
102
103 /**
104 * @return string
105 */
106 public function getCurrentLanguage()
107 {
108 return $this->currentLanguage;
109 }
110
111 /**
112 * @param string $language
113 */
114 public function setCurrentLanguage($language)
115 {
116 if (!$language) {
117 $language = $this->getDefaultLanguage();
118 }
119
120 $this->currentLanguage = $language;
121 }
122
123 /**
124 * @return string The default configured language.
125 */
126 public function getDefaultLanguage()
127 {
128 $generalSection = Config::getInstance()->General;
129
130 // the config may not be available (for example, during environment setup), so we default to 'en'
131 // if the config cannot be found.
132 return @$generalSection['default_language'] ?: 'en';
133 }
134
135 /**
136 * Generate javascript translations array
137 */
138 public function getJavascriptTranslations()
139 {
140 $clientSideTranslations = array();
141 foreach ($this->getClientSideTranslationKeys() as $id) {
142 list($plugin, $key) = explode('_', $id, 2);
143 $clientSideTranslations[$id] = $this->getTranslation($id, $this->currentLanguage, $plugin, $key);
144 }
145
146 $js = 'var translations = ' . json_encode($clientSideTranslations) . ';';
147 $js .= "\n" . 'if (typeof(piwik_translations) == \'undefined\') { var piwik_translations = new Object; }' .
148 'for(var i in translations) { piwik_translations[i] = translations[i];} ';
149 return $js;
150 }
151
152 /**
153 * Returns the list of client side translations by key. These translations will be outputted
154 * to the translation JavaScript.
155 */
156 private function getClientSideTranslationKeys()
157 {
158 $result = array();
159
160 /**
161 * Triggered before generating the JavaScript code that allows i18n strings to be used
162 * in the browser.
163 *
164 * Plugins should subscribe to this event to specify which translations
165 * should be available to JavaScript.
166 *
167 * Event handlers should add whole translation keys, ie, keys that include the plugin name.
168 *
169 * **Example**
170 *
171 * public function getClientSideTranslationKeys(&$result)
172 * {
173 * $result[] = "MyPlugin_MyTranslation";
174 * }
175 *
176 * @param array &$result The whole list of client side translation keys.
177 */
178 Piwik::postEvent('Translate.getClientSideTranslationKeys', array(&$result));
179
180 $result = array_unique($result);
181
182 return $result;
183 }
184
185 /**
186 * Add a directory containing translations.
187 *
188 * @param string $directory
189 */
190 public function addDirectory($directory)
191 {
192 if (isset($this->directories[$directory])) {
193 return;
194 }
195 // index by name to avoid duplicates
196 $this->directories[$directory] = $directory;
197
198 // clear currently loaded translations to force reloading them
199 $this->translations = array();
200 }
201
202 /**
203 * Should be used by tests only, and this method should eventually be removed.
204 */
205 public function reset()
206 {
207 $this->currentLanguage = $this->getDefaultLanguage();
208 $this->directories = array(PIWIK_INCLUDE_PATH . '/lang');
209 $this->translations = array();
210 }
211
212 /**
213 * @param string $translation
214 * @return null|string
215 */
216 public function findTranslationKeyForTranslation($translation)
217 {
218 foreach ($this->getAllTranslations() as $key => $translations) {
219 $possibleKey = array_search($translation, $translations);
220 if (!empty($possibleKey)) {
221 return $key . '_' . $possibleKey;
222 }
223 }
224
225 return null;
226 }
227
228 /**
229 * Returns all the translation messages loaded.
230 *
231 * @return array
232 */
233 public function getAllTranslations()
234 {
235 $this->loadTranslations($this->currentLanguage);
236
237 if (!isset($this->translations[$this->currentLanguage])) {
238 return array();
239 }
240
241 return $this->translations[$this->currentLanguage];
242 }
243
244 private function getTranslation($id, $lang, $plugin, $key)
245 {
246 $this->loadTranslations($lang);
247
248 if (isset($this->translations[$lang][$plugin])
249 && isset($this->translations[$lang][$plugin][$key])
250 ) {
251 return $this->translations[$lang][$plugin][$key];
252 }
253
254 /**
255 * Fallback for keys moved to new Intl plugin to avoid untranslated string in non core plugins
256 * @todo remove this in Piwik 3.0
257 */
258 if ($plugin != 'Intl') {
259 if (isset($this->translations[$lang]['Intl'])
260 && isset($this->translations[$lang]['Intl'][$key])
261 ) {
262 return $this->translations[$lang]['Intl'][$key];
263 }
264 }
265
266 // fallback
267 if ($lang !== $this->fallback) {
268 return $this->getTranslation($id, $this->fallback, $plugin, $key);
269 }
270
271 return $id;
272 }
273
274 private function loadTranslations($language)
275 {
276 if (empty($language) || isset($this->translations[$language])) {
277 return;
278 }
279
280 $this->translations[$language] = $this->loader->load($language, $this->directories);
281 }
282 }
283