| <?php |
|
|
| |
| |
| |
| |
| |
| |
|
|
| namespace Piwik\Translation; |
|
|
| use Piwik\Config; |
| use Piwik\Container\StaticContainer; |
| use Piwik\Log\LoggerInterface; |
| use Piwik\Piwik; |
| use Piwik\Translation\Loader\LoaderInterface; |
|
|
| |
| |
| |
| |
| |
| class Translator |
| { |
| |
| |
| |
| |
| |
| private $translations = []; |
|
|
| |
| |
| |
| private $currentLanguage; |
|
|
| |
| |
| |
| private $fallback = 'en'; |
|
|
| |
| |
| |
| |
| |
| private $directories = []; |
|
|
| |
| |
| |
| private $loader; |
|
|
| private const LIST_TYPE_AND = 'And'; |
| private const LIST_TYPE_OR = 'Or'; |
|
|
| public function __construct(LoaderInterface $loader, ?array $directories = null) |
| { |
| $this->loader = $loader; |
| $this->currentLanguage = $this->getDefaultLanguage(); |
|
|
| if ($directories === null) { |
| |
| $directories = [PIWIK_INCLUDE_PATH . '/lang']; |
| } |
| $this->directories = $directories; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| public static function clean($s) |
| { |
| return html_entity_decode(trim($s), ENT_QUOTES, 'UTF-8'); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function translate($translationId, $args = [], $language = null) |
| { |
| $args = is_array($args) ? $args : [$args]; |
| $translationId = $translationId ?? ''; |
|
|
| if (strpos($translationId, "_") !== false) { |
| [$plugin, $key] = explode("_", $translationId, 2); |
| $language = is_string($language) ? $language : $this->currentLanguage; |
|
|
| $translationId = $this->getTranslation($translationId, $language, $plugin, $key); |
| } |
|
|
| if (count($args) == 0) { |
| return str_replace('%%', '%', $translationId); |
| } |
| return vsprintf($translationId, $args); |
| } |
|
|
| |
| |
| |
| |
| |
| public function createAndListing(array $items, ?string $language = null): string |
| { |
| return $this->createListing(self::LIST_TYPE_AND, $items, $language); |
| } |
|
|
| |
| |
| |
| |
| |
| public function createOrListing(array $items, ?string $language = null): string |
| { |
| return $this->createListing(self::LIST_TYPE_OR, $items, $language); |
| } |
|
|
| |
| |
| |
| |
| private function createListing(string $listType, array $items, ?string $language = null): string |
| { |
| switch (count($items)) { |
| case 0: |
| return ''; |
| case 1: |
| return end($items); |
| case 2: |
| $pattern = $this->translate('Intl_ListPattern' . $listType . '2', [], $language); |
| return str_replace(['{0}', '{1}'], [$items[0], $items[1]], $pattern); |
| default: |
| $patternStart = $this->translate('Intl_ListPattern' . $listType . 'Start', [], $language); |
| $patternMiddle = $this->translate('Intl_ListPattern' . $listType . 'Middle', [], $language); |
| $patternEnd = $this->translate('Intl_ListPattern' . $listType . 'End', [], $language); |
|
|
| $result = $patternStart; |
|
|
| while (count($items) > 2) { |
| $pattern = count($items) > 3 ? $patternMiddle : $patternEnd; |
| $result = str_replace(['{0}', '{1}'], [array_shift($items), $pattern], $result); |
| } |
|
|
| return str_replace(['{0}', '{1}'], [$items[0], $items[1]], $result); |
| } |
| } |
|
|
| |
| |
| |
| public function getCurrentLanguage() |
| { |
| return $this->currentLanguage; |
| } |
|
|
| |
| |
| |
| public function setCurrentLanguage($language) |
| { |
| if (!$language) { |
| $language = $this->getDefaultLanguage(); |
| } |
|
|
| $this->currentLanguage = $language; |
| } |
|
|
| |
| |
| |
| public function getDefaultLanguage() |
| { |
| $generalSection = Config::getInstance()->General; |
|
|
| |
| |
| return @$generalSection['default_language'] ?: 'en'; |
| } |
|
|
| |
| |
| |
| public function getJavascriptTranslations() |
| { |
| $clientSideTranslations = array(); |
| foreach ($this->getClientSideTranslationKeys() as $id) { |
| if (strpos($id, '_') === false) { |
| StaticContainer::get(LoggerInterface::class)->warning( |
| 'Unexpected translation key found in client side translations: {translation_key}', |
| ['translation_key' => $id] |
| ); |
| continue; |
| } |
| [$plugin, $key] = explode('_', $id, 2); |
| $clientSideTranslations[$id] = $this->decodeEntitiesSafeForHTML($this->getTranslation($id, $this->currentLanguage, $plugin, $key)); |
| } |
|
|
| $js = 'var translations = ' . json_encode($clientSideTranslations) . ';'; |
| $js .= "\n" . 'if (typeof(piwik_translations) == \'undefined\') { var piwik_translations = new Object; }' . |
| 'for(var i in translations) { piwik_translations[i] = translations[i];} '; |
| return $js; |
| } |
|
|
| |
| |
| |
| private function decodeEntitiesSafeForHTML(string $text): string |
| { |
| |
| $text = str_replace( |
| ['>', '<'], |
| ['###gt###', '###lt###'], |
| $text |
| ); |
|
|
| |
| $text = html_entity_decode($text); |
|
|
| |
| return str_replace( |
| ['###gt###', '###lt###'], |
| ['>', '<'], |
| $text |
| ); |
| } |
|
|
| |
| |
| |
| |
| private function getClientSideTranslationKeys() |
| { |
| $result = array(); |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| Piwik::postEvent('Translate.getClientSideTranslationKeys', array(&$result)); |
|
|
| $result = array_unique($result); |
|
|
| return $result; |
| } |
|
|
| |
| |
| |
| |
| |
| public function addDirectory($directory) |
| { |
| if (isset($this->directories[$directory])) { |
| return; |
| } |
| |
| $this->directories[$directory] = $directory; |
|
|
| |
| $this->translations = array(); |
| } |
|
|
| |
| |
| |
| public function reset() |
| { |
| $this->currentLanguage = $this->getDefaultLanguage(); |
| $this->directories = array(PIWIK_INCLUDE_PATH . '/lang'); |
| $this->translations = array(); |
| } |
|
|
| |
| |
| |
| |
| public function findTranslationKeyForTranslation($translation) |
| { |
| foreach ($this->getAllTranslations() as $key => $translations) { |
| $possibleKey = array_search($translation, $translations); |
| if (!empty($possibleKey)) { |
| return $key . '_' . $possibleKey; |
| } |
| } |
|
|
| return null; |
| } |
|
|
| |
| |
| |
| |
| |
| public function getAllTranslations() |
| { |
| $this->loadTranslations($this->currentLanguage); |
|
|
| if (!isset($this->translations[$this->currentLanguage])) { |
| return array(); |
| } |
|
|
| return $this->translations[$this->currentLanguage]; |
| } |
|
|
| private function getTranslation($id, $lang, $plugin, $key) |
| { |
| $this->loadTranslations($lang); |
|
|
| if ( |
| isset($this->translations[$lang][$plugin]) |
| && isset($this->translations[$lang][$plugin][$key]) |
| ) { |
| return $this->translations[$lang][$plugin][$key]; |
| } |
|
|
| |
| |
| |
| |
| if ($plugin != 'Intl') { |
| if ( |
| isset($this->translations[$lang]['Intl']) |
| && isset($this->translations[$lang]['Intl'][$key]) |
| ) { |
| return $this->translations[$lang]['Intl'][$key]; |
| } |
| } |
|
|
| |
| if ($lang !== $this->fallback) { |
| return $this->getTranslation($id, $this->fallback, $plugin, $key); |
| } |
|
|
| return $id; |
| } |
|
|
| private function loadTranslations($language) |
| { |
| if (empty($language) || isset($this->translations[$language])) { |
| return; |
| } |
|
|
| $this->translations[$language] = $this->loader->load($language, $this->directories); |
| } |
| } |
|
|