diff --git a/config/global.ini.php b/config/global.ini.php index 0461f629fb307e4b5b12b022c7bb10ec5bd0ca2c..2793ca1b52fac51337fb078be8f9dade87284dbd 100644 --- a/config/global.ini.php +++ b/config/global.ini.php @@ -772,6 +772,7 @@ Plugins[] = TestRunner Plugins[] = BulkTracking Plugins[] = Resolution Plugins[] = DevicePlugins +Plugins[] = Intl [PluginsInstalled] PluginsInstalled[] = Diagnostics @@ -781,6 +782,7 @@ PluginsInstalled[] = UsersManager PluginsInstalled[] = SitesManager PluginsInstalled[] = Installation PluginsInstalled[] = Monolog +PluginsInstalled[] = Intl [APISettings] ; Any key/value pair can be added in this section, they will be available via the REST call diff --git a/core/Plugin/Manager.php b/core/Plugin/Manager.php index ce491935ef6f47b95b38d4ea11f80f99181fa8f4..cf7cc09baed435ff65dbe21c37f85789a812dfdc 100644 --- a/core/Plugin/Manager.php +++ b/core/Plugin/Manager.php @@ -73,6 +73,7 @@ class Manager 'Installation', 'SitesManager', 'UsersManager', + 'Intl', 'API', 'Proxy', 'LanguagesManager', diff --git a/plugins/Intl/Commands/GenerateIntl.php b/plugins/Intl/Commands/GenerateIntl.php new file mode 100644 index 0000000000000000000000000000000000000000..c0a524b28859e4923b2139eee6933b7610f66eda --- /dev/null +++ b/plugins/Intl/Commands/GenerateIntl.php @@ -0,0 +1,260 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ + +namespace Piwik\Plugins\Intl\Commands; + +use Piwik\Container\StaticContainer; +use Piwik\Development; +use Piwik\Filesystem; +use Piwik\Http; +use Piwik\Plugin\ConsoleCommand; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Console Command to generate Intl-data files for Piwik + * + * This script uses the master data of unicode-cldr/cldr-localenames-full repository to fetch available translations + */ +class GenerateIntl extends ConsoleCommand +{ + public function isEnabled() + { + return Development::isEnabled(); + } + + protected function configure() + { + $this->setName('translations:generate-intl-data') + ->setDescription('Generates Intl-data for Piwik'); + } + + protected function transformLangCode($langCode) + { + if (substr_count($langCode, '-') == 1) { + $langCodeParts = explode('-', $langCode, 2); + return sprintf('%s-%s', $langCodeParts[0], strtoupper($langCodeParts[1])); + } + return $langCode; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $piwikLanguages = \Piwik\Plugins\LanguagesManager\API::getInstance()->getAvailableLanguages(); + + $aliasesUrl = 'https://raw.githubusercontent.com/unicode-cldr/cldr-core/master/supplemental/aliases.json'; + $aliasesData = Http::fetchRemoteFile($aliasesUrl); + $aliasesData = json_decode($aliasesData, true); + $aliasesData = $aliasesData['supplemental']['metadata']['alias']['languageAlias']; + + $writePath = Filesystem::getPathToPiwikRoot() . '/plugins/Intl/lang/%s.json'; + + foreach ($piwikLanguages AS $langCode) { + + if ($langCode == 'dev') { + continue; + } + + $requestLangCode = $transformedLangCode = $this->transformLangCode($langCode); + + if (array_key_exists($requestLangCode, $aliasesData)) { + $requestLangCode = $aliasesData[$requestLangCode]['_replacement']; + } + + // fix some locales + $localFixes = array( + 'pt' => 'pt-PT', + 'pt-br' => 'pt', + 'zh-cn' => 'zh-Hans', + 'zh-tw' => 'zh-Hant' + ); + + if (array_key_exists($langCode, $localFixes)) { + $requestLangCode = $localFixes[$langCode]; + } + + $translations = (array)@json_decode(file_get_contents(sprintf($writePath, $langCode)), true); + + $this->fetchLanguageData($output, $transformedLangCode, $requestLangCode, $translations); + $this->fetchTerritoryData($output, $transformedLangCode, $requestLangCode, $translations); + $this->fetchCalendarData($output, $transformedLangCode, $requestLangCode, $translations); + + ksort($translations['Intl']); + + file_put_contents(sprintf($writePath, $langCode), json_encode($translations, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); + } + } + + protected function getEnglishLanguageName($code) + { + $languageDataUrl = 'https://raw.githubusercontent.com/unicode-cldr/cldr-localenames-full/master/main/%s/languages.json'; + + static $languageData = array(); + + try { + if (empty($languageData)) { + $languageData = Http::fetchRemoteFile(sprintf($languageDataUrl, 'en')); + $languageData = json_decode($languageData, true); + $languageData = $languageData['main']['en']['localeDisplayNames']['languages']; + } + + return (array_key_exists($code, $languageData) && $languageData[$code] != $code) ? $languageData[$code] : ''; + } catch (\Exception $e) { + } + + return ''; + } + + protected function fetchLanguageData(OutputInterface $output, $langCode, $requestLangCode, &$translations) + { + $languageCodes = array_keys(StaticContainer::get('Piwik\Intl\Data\Provider\LanguageDataProvider')->getLanguageList()); + + $languageDataUrl = 'https://raw.githubusercontent.com/unicode-cldr/cldr-localenames-full/master/main/%s/languages.json'; + + try { + $languageData = Http::fetchRemoteFile(sprintf($languageDataUrl, $requestLangCode)); + $languageData = json_decode($languageData, true); + $languageData = $languageData['main'][$requestLangCode]['localeDisplayNames']['languages']; + + if (empty($languageData)) { + throw new \Exception(); + } + + foreach ($languageCodes AS $code) { + if (!empty($languageData[$code]) && $languageData[$code] != $code) { + $translations['Intl']['Language_' . $code] = $languageData[$code]; + } + } + + if (array_key_exists($langCode, $languageData) && $languageData[$langCode] != $langCode) { + $translations['Intl']['OriginalLanguageName'] = $languageData[$langCode]; + } else if (array_key_exists($requestLangCode, $languageData) && $languageData[$requestLangCode] != $requestLangCode) { + $translations['Intl']['OriginalLanguageName'] = $languageData[$requestLangCode]; + } + $translations['Intl']['EnglishLanguageName'] = $this->getEnglishLanguageName($langCode) ? $this->getEnglishLanguageName($langCode) : $this->getEnglishLanguageName($requestLangCode); + + $output->writeln('Saved language data for ' . $langCode); + } catch (\Exception $e) { + $output->writeln('Unable to import language data for ' . $langCode); + } + } + + protected function fetchTerritoryData(OutputInterface $output, $langCode, $requestLangCode, &$translations) + { + $territoryDataUrl = 'https://raw.githubusercontent.com/unicode-cldr/cldr-localenames-full/master/main/%s/territories.json'; + + $countryCodes = array_keys(StaticContainer::get('Piwik\Intl\Data\Provider\RegionDataProvider')->getCountryList()); + $countryCodes = array_map('strtoupper', $countryCodes); + + $continentMapping = array( + "afr" => "002", + "amc" => "013", + "amn" => "003", + "ams" => "005", + "ant" => "AQ", + "asi" => "142", + "eur" => "150", + "oce" => "009" + ); + + try { + $territoryData = Http::fetchRemoteFile(sprintf($territoryDataUrl, $requestLangCode)); + $territoryData = json_decode($territoryData, true); + $territoryData = $territoryData['main'][$requestLangCode]['localeDisplayNames']['territories']; + + foreach ($countryCodes AS $code) { + if (!empty($territoryData[$code]) && $territoryData[$code] != $code) { + $translations['Intl']['Country_' . $code] = $territoryData[$code]; + } + } + + foreach ($continentMapping as $shortCode => $code) { + if (!empty($territoryData[$code]) && $territoryData[$code] != $code) { + $translations['Intl']['Continent_' . $shortCode] = $territoryData[$code]; + } + } + + $output->writeln('Saved territory data for ' . $langCode); + } catch (\Exception $e) { + $output->writeln('Unable to import territory data for ' . $langCode); + } + } + + protected function fetchCalendarData(OutputInterface $output, $langCode, $requestLangCode, &$translations) + { + $calendarDataUrl = 'https://raw.githubusercontent.com/unicode-cldr/cldr-dates-full/master/main/%s/ca-gregorian.json'; + + try { + $calendarData = Http::fetchRemoteFile(sprintf($calendarDataUrl, $requestLangCode)); + $calendarData = json_decode($calendarData, true); + $calendarData = $calendarData['main'][$requestLangCode]['dates']['calendars']['gregorian']; + + for ($i = 1; $i <= 12; $i++) { + $translations['Intl']['ShortMonth_' . $i] = $calendarData['months']['format']['abbreviated'][$i]; + $translations['Intl']['LongMonth_' . $i] = $calendarData['months']['format']['wide'][$i]; + } + + $days = array( + 1 => 'mon', + 2 => 'tue', + 3 => 'wed', + 4 => 'thu', + 5 => 'fri', + 6 => 'sat', + 7 => 'sun' + ); + + foreach ($days AS $nr => $day) { + $translations['Intl']['ShortDay_' . $nr] = $calendarData['days']['format']['abbreviated'][$day]; + $translations['Intl']['LongDay_' . $nr] = $calendarData['days']['format']['wide'][$day]; + } + + $days = array( + 'Mo' => 'mon', + 'Tu' => 'tue', + 'We' => 'wed', + 'Th' => 'thu', + 'Fr' => 'fri', + 'Sa' => 'sat', + 'Su' => 'sun' + ); + + foreach ($days AS $nr => $day) { + $translations['Intl']['Day' . $nr] = $calendarData['days']['format']['short'][$day]; + } + + + $output->writeln('Saved calendar data for ' . $langCode); + } catch (\Exception $e) { + $output->writeln('Unable to import calendar data for ' . $langCode); + } + + $dateFieldsUrl = 'https://raw.githubusercontent.com/unicode-cldr/cldr-dates-full/master/main/%s/dateFields.json'; + + try { + $dateFieldData = Http::fetchRemoteFile(sprintf($dateFieldsUrl, $requestLangCode)); + $dateFieldData = json_decode($dateFieldData, true); + $dateFieldData = $dateFieldData['main'][$requestLangCode]['dates']['fields']; + + #$translations['Intl']['Period_Week'] = $dateFieldData['week']['displayName']; + #$translations['Intl']['Period_Year'] = $dateFieldData['year']['displayName']; + #$translations['Intl']['Period_Day'] = $dateFieldData['day']['displayName']; + #$translations['Intl']['Period_Month'] = $dateFieldData['month']['displayName']; + $translations['Intl']['YearShort'] = $dateFieldData['year-narrow']['displayName']; + $translations['Intl']['Today'] = $dateFieldData['day']['relative-type-0']; + $translations['Intl']['Yesterday'] = $dateFieldData['day']['relative-type--1']; + + $output->writeln('Saved date fields for ' . $langCode); + } catch (\Exception $e) { + $output->writeln('Unable to import date fields for ' . $langCode); + } + } + + +} diff --git a/plugins/Intl/Intl.php b/plugins/Intl/Intl.php new file mode 100644 index 0000000000000000000000000000000000000000..29099884378d08dba80f90ea9e9d57a13c87e07e --- /dev/null +++ b/plugins/Intl/Intl.php @@ -0,0 +1,14 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ +namespace Piwik\Plugins\Intl; + +class Intl extends \Piwik\Plugin +{ + +} diff --git a/plugins/LanguagesManager/Commands/GenerateIntl.php b/plugins/LanguagesManager/Commands/GenerateIntl.php deleted file mode 100644 index 5b8af855bda2cd588451dcf7fd86950e9b661d84..0000000000000000000000000000000000000000 --- a/plugins/LanguagesManager/Commands/GenerateIntl.php +++ /dev/null @@ -1,115 +0,0 @@ -<?php -/** - * Piwik - free/libre analytics platform - * - * @link http://piwik.org - * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later - * - */ - -namespace Piwik\Plugins\LanguagesManager\Commands; - -use Aws\CloudFront\Exception\Exception; -use Piwik\Container\StaticContainer; -use Piwik\Filesystem; -use Piwik\Http; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; - -/** - * Console Command to generate Intl-data files for Piwik - * - * This script uses the master data of unicode-cldr/cldr-localenames-full repository to fetch available translations - */ -class GenerateIntl extends TranslationBase -{ - protected function configure() - { - $this->setName('translations:generate-intl-data') - ->setDescription('Generates Intl-data for Piwik'); - } - - protected function execute(InputInterface $input, OutputInterface $output) - { - $piwikLanguages = \Piwik\Plugins\LanguagesManager\API::getInstance()->getAvailableLanguages(); - $languageCodes = array_keys(StaticContainer::get('Piwik\Intl\Data\Provider\LanguageDataProvider')->getLanguageList()); - $countryCodes = array_keys(StaticContainer::get('Piwik\Intl\Data\Provider\RegionDataProvider')->getCountryList()); - $countryCodes = array_map('strtoupper', $countryCodes); - - $languageDataUrl = 'https://raw.githubusercontent.com/unicode-cldr/cldr-localenames-full/master/main/%s/languages.json'; - $languageWritePath = Filesystem::getPathToPiwikRoot() . '/core/Intl/Data/Resources/languages/%s.json'; - - $countryDataUrl = 'https://raw.githubusercontent.com/unicode-cldr/cldr-localenames-full/master/main/%s/territories.json'; - $countryWritePath = Filesystem::getPathToPiwikRoot() . '/core/Intl/Data/Resources/countries/%s.json'; - - - foreach ($piwikLanguages AS $langCode) { - - if ($langCode == 'dev') { - continue; - } - - $requestLangCode = $langCode; - - if (substr_count($langCode, '-') == 1) { - $langCodeParts = explode('-', $langCode, 2); - $requestLangCode = sprintf('%s-%s', $langCodeParts[0], strtoupper($langCodeParts[1])); - } - - if ($langCode == 'zh-cn') { - $requestLangCode = 'zh-Hans'; - } - - if ($langCode == 'zh-tw') { - $requestLangCode = 'zh-Hant'; - } - - try { - $languageData = Http::fetchRemoteFile(sprintf($languageDataUrl, $requestLangCode)); - $languageData = json_decode($languageData, true); - $languageData = $languageData['main'][$requestLangCode]['localeDisplayNames']['languages']; - - $translations = (array) @json_decode(file_get_contents(sprintf($languageWritePath, $langCode))); - - if (empty($translations)) { - $translations = array_fill_keys($languageCodes, ''); - } - - foreach ($languageCodes AS $code) { - if (!empty($languageData[$code]) && $languageData[$code] != $code) { - $translations[$code] = $languageData[$code]; - } - } - - file_put_contents(sprintf($languageWritePath, $langCode), json_encode($translations, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE)); - $output->writeln('Saved language data for '.$langCode); - } catch (Exception $e) { - $output->writeln('Unable to import language data for '.$langCode); - } - - try { - $countryData = Http::fetchRemoteFile(sprintf($countryDataUrl, $requestLangCode)); - $countryData = json_decode($countryData, true); - $countryData = $countryData['main'][$requestLangCode]['localeDisplayNames']['territories']; - - $translations = (array) @json_decode(file_get_contents(sprintf($countryWritePath, $langCode))); - - if (empty($translations)) { - $translations = array_fill_keys($countryCodes, ''); - } - - foreach ($countryCodes AS $code) { - if (!empty($countryData[$code]) && $countryData[$code] != $code) { - $translations[$code] = $countryData[$code]; - } - } - - file_put_contents(sprintf($countryWritePath, $langCode), json_encode($translations, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE)); - $output->writeln('Saved country data for '.$langCode); - } catch (Exception $e) { - $output->writeln('Unable to import country data for '.$langCode); - } - - } - } -}