PDF rausgenommen

This commit is contained in:
aschwarz
2023-01-23 11:03:31 +01:00
parent 82d562a322
commit a6523903eb
28078 changed files with 4247552 additions and 2 deletions

View File

@ -0,0 +1,72 @@
<?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\Translation\Loader;
/**
* Loads a pseudo-language for developers where translation are equal to translation ids.
*/
class DevelopmentLoader implements LoaderInterface
{
const LANGUAGE_ID = 'dev';
/**
* Decorated loader.
*
* @var LoaderInterface
*/
private $loader;
/**
* @var string
*/
private $fallbackLanguage = 'en';
/**
* @param LoaderInterface $loader Decorate another loader to add the pseudo-language.
*/
public function __construct(LoaderInterface $loader)
{
$this->loader = $loader;
}
/**
* {@inheritdoc}
*/
public function load($language, array $directories)
{
if ($language !== self::LANGUAGE_ID) {
return $this->loader->load($language, $directories);
}
return $this->getDevelopmentTranslations($directories);
}
private function getDevelopmentTranslations(array $directories)
{
$fallbackTranslations = $this->loader->load($this->fallbackLanguage, $directories);
$translations = array();
foreach ($fallbackTranslations as $section => $sectionFallbackTranslations) {
$translationIds = array_keys($sectionFallbackTranslations);
$sectionTranslations = $this->prefixTranslationsWithSection($section, $translationIds);
$translations[$section] = array_combine($translationIds, $sectionTranslations);
}
return $translations;
}
private function prefixTranslationsWithSection($section, $translationIds)
{
return array_map(function ($translation) use ($section) {
return $section . '_' . $translation;
}, $translationIds);
}
}

View File

@ -0,0 +1,64 @@
<?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\Translation\Loader;
use Piwik\Common;
/**
* Loads translations from JSON files.
*/
class JsonFileLoader implements LoaderInterface
{
/**
* {@inheritdoc}
*/
public function load($language, array $directories)
{
if (empty($language)) {
return array();
}
$translations = array();
foreach ($directories as $directory) {
$filename = $directory . '/' . $language . '.json';
if (! file_exists($filename)) {
continue;
}
$translations = array_replace_recursive(
$translations,
$this->loadFile($filename)
);
}
return $translations;
}
private function loadFile($filename)
{
$data = file_get_contents($filename);
$translations = json_decode($data, true);
if (is_null($translations) && Common::hasJsonErrorOccurred()) {
throw new \Exception(sprintf(
'Not able to load translation file %s: %s',
$filename,
Common::getLastJsonError()
));
}
if (!is_array($translations)) {
return array();
}
return $translations;
}
}

View File

@ -0,0 +1,65 @@
<?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\Translation\Loader;
use Piwik\Cache;
/**
* Caches the translations loaded by another loader.
*/
class LoaderCache implements LoaderInterface
{
/**
* @var LoaderInterface
*/
private $loader;
/**
* @var Cache\Lazy
*/
private $cache;
public function __construct(LoaderInterface $loader, Cache\Lazy $cache)
{
$this->loader = $loader;
$this->cache = $cache;
}
/**
* {@inheritdoc}
*/
public function load($language, array $directories)
{
if (empty($language)) {
return array();
}
$cacheKey = $this->getCacheKey($language, $directories);
$translations = $this->cache->fetch($cacheKey);
if (empty($translations) || !is_array($translations)) {
$translations = $this->loader->load($language, $directories);
$this->cache->save($cacheKey, $translations, 43200); // ttl=12hours
}
return $translations;
}
private function getCacheKey($language, array $directories)
{
$cacheKey = 'Translations-' . $language . '-';
// in case loaded plugins change (ie Tests vs Tracker vs UI etc)
$cacheKey .= sha1(implode('', $directories));
return $cacheKey;
}
}

View File

@ -0,0 +1,23 @@
<?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\Translation\Loader;
/**
* Loads translations.
*/
interface LoaderInterface
{
/**
* @param string $language
* @param mixed[] $directories Directories containing translation files.
* @throws \Exception The translation file was not found
* @return string[] Translations.
*/
public function load($language, array $directories);
}

View File

@ -0,0 +1,148 @@
<?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\Translation\Transifex;
use Exception;
use Piwik\Cache;
use Piwik\Exception\AuthenticationFailedException;
use Piwik\Http;
class API
{
protected $apiUrl = 'https://www.transifex.com/api/2/';
protected $username = '';
protected $password = '';
protected $projectSlug = '';
public function __construct($username, $password, $project = 'matomo')
{
$this->username = $username;
$this->password = $password;
$this->projectSlug = $project;
}
/**
* Returns all resources available on Transifex project
*
* @return array
*/
public function getAvailableResources()
{
$cache = Cache::getTransientCache();
$cacheId = 'transifex_resources_' . $this->projectSlug;
$resources = $cache->fetch($cacheId);
if (empty($resources)) {
$apiPath = 'project/' . $this->projectSlug . '/resources';
$resources = $this->getApiResults($apiPath);
$cache->save($cacheId, $resources);
}
return $resources;
}
/**
* Checks if the given resource exists in Transifex project
*
* @param string $resource
* @return bool
*/
public function resourceExists($resource)
{
$resources = $this->getAvailableResources();
foreach ($resources as $res) {
if ($res->slug == $resource) {
return true;
}
}
return false;
}
/**
* Returns all language codes the transifex project is available for
*
* @return array
* @throws AuthenticationFailedException
* @throws Exception
*/
public function getAvailableLanguageCodes()
{
$cache = Cache::getTransientCache();
$cacheId = 'transifex_languagescodes_' . $this->projectSlug;
$languageCodes = $cache->fetch($cacheId);
if (empty($languageCodes)) {
$apiData = $this->getApiResults('project/' . $this->projectSlug . '/languages');
foreach ($apiData as $languageData) {
$languageCodes[] = $languageData->language_code;
}
$cache->save($cacheId, $languageCodes);
}
return $languageCodes;
}
/**
* Returns statistic data for the given resource
*
* @param string $resource e.g. piwik-base, piwik-plugin-api,...
* @return array
* @throws AuthenticationFailedException
* @throws Exception
*/
public function getStatistics($resource)
{
return $this->getApiResults('project/' . $this->projectSlug . '/resource/' . $resource . '/stats/');
}
/**
* Return the translations for the given resource and language
*
* @param string $resource e.g. piwik-base, piwik-plugin-api,...
* @param string $language e.g. de, pt_BR, hy,...
* @param bool $raw if true plain response wil be returned (unparsed json)
* @return mixed
* @throws AuthenticationFailedException
* @throws Exception
*/
public function getTranslations($resource, $language, $raw = false)
{
if ($this->resourceExists($resource)) {
$apiPath = 'project/' . $this->projectSlug . '/resource/' . $resource . '/translation/' . $language . '/?mode=onlytranslated&file';
return $this->getApiResults($apiPath, $raw);
}
return null;
}
/**
* Returns response for API request with given path
*
* @param $apiPath
* @param bool $raw
* @return mixed
* @throws AuthenticationFailedException
* @throws Exception
*/
protected function getApiResults($apiPath, $raw = false)
{
$apiUrl = $this->apiUrl . $apiPath;
$response = Http::sendHttpRequest($apiUrl, 1000, null, null, 5, false, false, true, 'GET', $this->username, $this->password);
$httpStatus = $response['status'];
$response = $response['data'];
if ($httpStatus == 401) {
throw new AuthenticationFailedException();
} elseif ($httpStatus != 200) {
throw new Exception('Error while getting API results', $httpStatus);
}
return $raw ? $response : json_decode($response);
}
}

View File

@ -0,0 +1,271 @@
<?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\Translation;
use Piwik\Config;
use Piwik\Piwik;
use Piwik\Plugin;
use Piwik\Translation\Loader\LoaderInterface;
/**
* Translates messages.
*
* @api
*/
class Translator
{
/**
* Contains the translated messages, indexed by the language name.
*
* @var array
*/
private $translations = array();
/**
* @var string
*/
private $currentLanguage;
/**
* @var string
*/
private $fallback = 'en';
/**
* Directories containing the translations to load.
*
* @var string[]
*/
private $directories = array();
/**
* @var LoaderInterface
*/
private $loader;
public function __construct(LoaderInterface $loader, array $directories = null)
{
$this->loader = $loader;
$this->currentLanguage = $this->getDefaultLanguage();
if ($directories === null) {
// TODO should be moved out of this class
$directories = array(PIWIK_INCLUDE_PATH . '/lang');
}
$this->directories = $directories;
}
/**
* Returns an internationalized string using a translation ID. If a translation
* cannot be found for the ID, the ID is returned.
*
* @param string $translationId Translation ID, eg, `General_Date`.
* @param array|string|int $args `sprintf` arguments to be applied to the internationalized
* string.
* @param string|null $language Optionally force the language.
* @return string The translated string or `$translationId`.
* @api
*/
public function translate($translationId, $args = array(), $language = null)
{
$args = is_array($args) ? $args : array($args);
if (strpos($translationId, "_") !== false) {
list($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);
}
/**
* @return string
*/
public function getCurrentLanguage()
{
return $this->currentLanguage;
}
/**
* @param string $language
*/
public function setCurrentLanguage($language)
{
if (!$language) {
$language = $this->getDefaultLanguage();
}
$this->currentLanguage = $language;
}
/**
* @return string The default configured language.
*/
public function getDefaultLanguage()
{
$generalSection = Config::getInstance()->General;
// the config may not be available (for example, during environment setup), so we default to 'en'
// if the config cannot be found.
return @$generalSection['default_language'] ?: 'en';
}
/**
* Generate javascript translations array
*/
public function getJavascriptTranslations()
{
$clientSideTranslations = array();
foreach ($this->getClientSideTranslationKeys() as $id) {
list($plugin, $key) = explode('_', $id, 2);
$clientSideTranslations[$id] = $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;
}
/**
* Returns the list of client side translations by key. These translations will be outputted
* to the translation JavaScript.
*/
private function getClientSideTranslationKeys()
{
$result = array();
/**
* Triggered before generating the JavaScript code that allows i18n strings to be used
* in the browser.
*
* Plugins should subscribe to this event to specify which translations
* should be available to JavaScript.
*
* Event handlers should add whole translation keys, ie, keys that include the plugin name.
*
* **Example**
*
* public function getClientSideTranslationKeys(&$result)
* {
* $result[] = "MyPlugin_MyTranslation";
* }
*
* @param array &$result The whole list of client side translation keys.
*/
Piwik::postEvent('Translate.getClientSideTranslationKeys', array(&$result));
$result = array_unique($result);
return $result;
}
/**
* Add a directory containing translations.
*
* @param string $directory
*/
public function addDirectory($directory)
{
if (isset($this->directories[$directory])) {
return;
}
// index by name to avoid duplicates
$this->directories[$directory] = $directory;
// clear currently loaded translations to force reloading them
$this->translations = array();
}
/**
* Should be used by tests only, and this method should eventually be removed.
*/
public function reset()
{
$this->currentLanguage = $this->getDefaultLanguage();
$this->directories = array(PIWIK_INCLUDE_PATH . '/lang');
$this->translations = array();
}
/**
* @param string $translation
* @return null|string
*/
public function findTranslationKeyForTranslation($translation)
{
foreach ($this->getAllTranslations() as $key => $translations) {
$possibleKey = array_search($translation, $translations);
if (!empty($possibleKey)) {
return $key . '_' . $possibleKey;
}
}
return null;
}
/**
* Returns all the translation messages loaded.
*
* @return array
*/
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];
}
/**
* Fallback for keys moved to new Intl plugin to avoid untranslated string in non core plugins
* @todo remove this in Piwik 3.0
*/
if ($plugin != 'Intl') {
if (isset($this->translations[$lang]['Intl'])
&& isset($this->translations[$lang]['Intl'][$key])
) {
return $this->translations[$lang]['Intl'][$key];
}
}
// fallback
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);
}
}