/** * Output translations to string * * @param array $translations Array of translations ( key => translated string ) * @return string */ public static function outputTranslation($translations) { if (!self::$baseTranslation) { self::$baseTranslation = self::loadTranslation('en'); } $en = self::$baseTranslation; $output = array('<?php', '$translations = array('); $deferoutput = array(); /* write all the translations that exist in en.php */ foreach ($en as $key => $en_translation) { if (isset($translations[$key]) && !empty($translations[$key])) { $tmp = self::quote($translations[$key]); $output[] = "\t'{$key}' => {$tmp},"; } } /* write the remaining translations (that don't exist in en.php) */ foreach ($translations as $key => $translation) { if (!isset($en[$key]) && !empty($translation)) { $tmp = self::quote($translation); $deferoutput[] = "\t'{$key}' => {$tmp},"; } } if (count($deferoutput) > 0) { $output[] = "\n\t// FOR REVIEW"; $output = array_merge($output, $deferoutput); } $output[] = ');'; return implode($output, "\n") . "\n"; }
function test_saveTranslation() { $path = Piwik_TranslationWriter::getTranslationPath('en', 'tmp'); $translations = array('General_Locale' => 'en_CA.UTF-8', 'General_Id' => 'Id', 'Goals_Goals' => 'Goals', 'Plugin_Body' => "Message\nBody"); @unlink($path); $rc = Piwik_TranslationWriter::saveTranslation($translations, $path); $this->assertTrue($rc !== false); $contents = file_get_contents($path); $expected = "<?php\n\$translations = array(\n\t'General_Locale' => 'en_CA.UTF-8',\n\t'General_Id' => 'Id',\n\t'Goals_Goals' => 'Goals',\n\n\t// FOR REVIEW\n\t'Plugin_Body' => 'Message\nBody',\n);\n"; if (Piwik_Common::isWindows()) { $expected = str_replace("\r\n", "\n", $expected); } $this->assertEqual($contents, $expected); }
function addMenus() { $goals = Piwik_Tracker_GoalManager::getGoalDefinitions(Piwik_Common::getRequestVar('idSite', null, 'int')); if (count($goals) == 0) { Piwik_AddMenu('Goals_Goals', '', array('module' => 'Goals', 'action' => 'addNewGoal'), true, 25); Piwik_AddMenu('Goals_Goals', 'Goals_AddNewGoal', array('module' => 'Goals', 'action' => 'addNewGoal')); } else { Piwik_AddMenu('Goals_Goals', '', array('module' => 'Goals', 'action' => 'index'), true, 25); Piwik_AddMenu('Goals_Goals', 'Goals_Overview', array('module' => 'Goals', 'action' => 'index'), true, 1); foreach ($goals as $goal) { Piwik_AddMenu('Goals_Goals', str_replace('%', '%%', Piwik_TranslationWriter::clean($goal['name'])), array('module' => 'Goals', 'action' => 'goalReport', 'idGoal' => $goal['idgoal'])); } } }
function addMenus() { $idSite = Piwik_Common::getRequestVar('idSite', null, 'int'); $goals = Piwik_Goals_API::getInstance()->getGoals($idSite); $mainGoalMenu = $this->getGoalCategoryName($idSite); $site = new Piwik_Site($idSite); if (count($goals) == 0) { Piwik_AddMenu($mainGoalMenu, '', array('module' => 'Goals', 'action' => $site->isEcommerceEnabled() ? 'ecommerceReport' : 'addNewGoal', 'idGoal' => $site->isEcommerceEnabled() ? Piwik_Archive::LABEL_ECOMMERCE_ORDER : null), true, 25); if ($site->isEcommerceEnabled()) { Piwik_AddMenu($mainGoalMenu, 'Goals_Ecommerce', array('module' => 'Goals', 'action' => 'ecommerceReport', 'idGoal' => Piwik_Archive::LABEL_ECOMMERCE_ORDER), true, 1); } Piwik_AddMenu($mainGoalMenu, 'Goals_AddNewGoal', array('module' => 'Goals', 'action' => 'addNewGoal')); } else { Piwik_AddMenu($mainGoalMenu, '', array('module' => 'Goals', 'action' => $site->isEcommerceEnabled() ? 'ecommerceReport' : 'index', 'idGoal' => $site->isEcommerceEnabled() ? Piwik_Archive::LABEL_ECOMMERCE_ORDER : null), true, 25); if ($site->isEcommerceEnabled()) { Piwik_AddMenu($mainGoalMenu, 'Goals_Ecommerce', array('module' => 'Goals', 'action' => 'ecommerceReport', 'idGoal' => Piwik_Archive::LABEL_ECOMMERCE_ORDER), true, 1); } Piwik_AddMenu($mainGoalMenu, 'Goals_GoalsOverview', array('module' => 'Goals', 'action' => 'index'), true, 2); foreach ($goals as $goal) { Piwik_AddMenu($mainGoalMenu, str_replace('%', '%%', Piwik_TranslationWriter::clean($goal['name'])), array('module' => 'Goals', 'action' => 'goalReport', 'idGoal' => $goal['idgoal'])); } } }
private function writeCleanedTranslationFile($translations, $language) { $path = Piwik_TranslationWriter::getTranslationPath($language, 'tmp'); Piwik_TranslationWriter::saveTranslation($translations, $path); $this->fail('Translation file errors detected in ' . $language . '... Wrote cleaned translation file in: ' . $path . ".\n\t\t\t\t\tYou can copy the cleaned files to /lang/<br/>\n"); }
/** * test all languages * * @group Plugins * @group LanguagesManager */ function testGetTranslationsForLanguages() { $allLanguages = Piwik_Common::getLanguagesList(); $allCountries = Piwik_Common::getCountriesList(); $englishStrings = Piwik_LanguagesManager_API::getInstance()->getTranslationsForLanguage('en'); $englishStringsWithParameters = array(); $expectedLanguageKeys = array(); foreach ($englishStrings as $englishString) { $stringLabel = $englishString['label']; $stringValue = $englishString['value']; $count = $this->getCountParametersToReplace($stringValue); if ($count > 0) { $englishStringsWithParameters[$stringLabel] = $count; } $englishStringsIndexed[$stringLabel] = $stringValue; $expectedLanguageKeys[] = $stringLabel; } self::$englishStringsIndexed = $englishStringsIndexed; // we also test that none of the language php files outputs any character on the screen (eg. space before the <?php) $languages = Piwik_LanguagesManager_API::getInstance()->getAvailableLanguages(); $output = array(); foreach ($languages as $language) { self::$errors = array(); if ($language == 'en') { continue; } ob_start(); $writeCleanedFile = false; $strings = Piwik_LanguagesManager_API::getInstance()->getTranslationsForLanguage($language); $content = ob_get_flush(); $serializedStrings = serialize($strings); $invalids = array("<script", 'document.', 'javascript:', 'src=', 'BACKGROUND=', 'onload='); foreach ($invalids as $invalid) { $this->assertTrue(stripos($serializedStrings, $invalid) === false, "{$language}: language file containing javascript"); } $this->assertTrue(count($strings) > 100, "{$language}: expecting at least 100 translations in the language file"); $this->assertTrue(strlen($content) == 0, "{$language}: buffer was " . strlen($content) . " long but should be zero. Translation file for '{$language}' must be buggy."); $cleanedStrings = array(); foreach ($strings as $string) { $stringLabel = $string['label']; $stringValue = $string['value']; $plugin = substr($stringLabel, 0, strpos($stringLabel, '_')); $plugins[$plugin] = true; // Testing that the translated string is not empty => '', if (empty($stringValue) || trim($stringValue) === '') { $writeCleanedFile = true; self::$errors[] = "{$language}: The string {$stringLabel} is empty in the translation file, removing the line."; $cleanedStrings[$stringLabel] = false; } elseif (!in_array($stringLabel, $expectedLanguageKeys) && !in_array($plugin, array('GeoIP', 'Forecast', 'EntryPage', 'UserLanguage'))) { $writeCleanedFile = true; self::$errors[] = "{$language}: The string {$stringLabel} was not found in the English language file, removing the line."; $cleanedStrings[$stringLabel] = false; } else { // checking that translated strings have the same number of %s as the english source strings if (isset($englishStringsWithParameters[$stringLabel])) { $englishParametersCount = $englishStringsWithParameters[$stringLabel]; $countTranslation = $this->getCountParametersToReplace($stringValue); if ($englishParametersCount != $countTranslation) { // Write fixed file in given location // Will trigger a ->fail() $writeCleanedFile = true; self::$errors[] = "{$language}: The string {$stringLabel} has {$englishParametersCount} parameters in English, but {$countTranslation} in this translation."; } else { $cleanedStrings[$stringLabel] = $stringValue; } } else { $cleanedStrings[$stringLabel] = $stringValue; } } // If the translation is the same as in English, we remove it from the translation file (as it might have been copied by // the translator but this would skew translation stats if (isset($englishStringsIndexed[$stringLabel]) && $englishStringsIndexed[$stringLabel] == $stringValue && strpos($stringLabel, 'General_') === false && strpos($stringLabel, 'CoreHome_') === false && strpos($stringLabel, 'UserCountry_') === false && $language != 'de') { $writeCleanedFile = true; self::$errors[] = "{$language}: The string {$stringLabel} is the same as in English, removing..."; $cleanedStrings[$stringLabel] = false; } // remove excessive line breaks (and leading/trailing whitespace) from translations if (!empty($cleanedStrings[$stringLabel])) { $stringNoLineBreak = trim($cleanedStrings[$stringLabel]); if ($stringLabel != 'Login_MailPasswordChangeBody') { $stringNoLineBreak = str_replace(array("\n", "\r"), " ", $stringNoLineBreak); } if ($cleanedStrings[$stringLabel] !== $stringNoLineBreak) { self::$errors[] = "{$language}: found unnecessary whitespace in some strings in {$stringLabel}"; $writeCleanedFile = true; $cleanedStrings[$stringLabel] = $stringNoLineBreak; } } // Test locale if ($stringLabel == 'General_Locale' && !empty($cleanedStrings[$stringLabel])) { if (!preg_match('/^([a-z]{2})_([A-Z]{2})\\.UTF-8$/', $cleanedStrings[$stringLabel], $matches)) { $this->fail("{$language}: invalid locale in {$stringLabel}"); } else { if (!array_key_exists($matches[1], $allLanguages)) { $this->fail("{$language}: invalid language code in {$stringLabel}"); } else { if (!array_key_exists(strtolower($matches[2]), $allCountries)) { $this->fail("{$language}: invalid region (country code) in {$stringLabel}"); } } } } if (isset($cleanedStrings[$stringLabel])) { $currentString = $cleanedStrings[$stringLabel]; $decoded = Piwik_TranslationWriter::clean($currentString); if ($currentString != $decoded) { self::$errors[] = "{$language}: found encoded entities in {$stringLabel}, converting entities to characters"; $writeCleanedFile = true; $cleanedStrings[$stringLabel] = $decoded; } } } $this->assertTrue(!empty($cleanedStrings['General_TranslatorName']), "{$language}: translator info not specified"); $this->assertTrue(!empty($cleanedStrings['General_TranslatorEmail']), "{$language}: translator email not specified"); if (!empty($cleanedStrings['General_LayoutDirection']) && !in_array($cleanedStrings['General_LayoutDirection'], array('rtl', 'ltr'))) { $writeCleanedFile = true; $cleanedStrings['General_LayoutDirection'] = false; self::$errors[] = "{$language}: General_LayoutDirection must be rtl or ltr"; } if ($writeCleanedFile) { $path = Piwik_TranslationWriter::getTranslationPath($language, 'tmp'); // Reorder cleaned up translations as the same order as en.php uksort($cleanedStrings, array($this, 'sortTranslationsKeys')); Piwik_TranslationWriter::saveTranslation($cleanedStrings, $path); $output[] = implode("<br>\n", self::$errors) . "\n" . 'Translation file errors detected in ' . $language . '... Wrote cleaned translation file in: ' . $path . ".\n You can copy the cleaned files to /lang/\n"; } } if (!empty($output)) { $this->fail(implode(",", $output)); } }