translate($key, $params); if ($value !== null) return $value; } // Add a missing key to the debug notes. $notes =& Registry::get('system.debug.notes'); $notes[] = array('debug.notes.missingLocaleKey', array('key' => $key)); // Add some octothorpes to missing keys to make them more obvious return '##' . $key . '##'; } /** * Get the filename for the locale file given a locale name. */ function getMainLocaleFilename($locale) { return "locale/$locale/locale.xml"; } /** * Initialize the locale system. */ function initialize() { // Use defaults if locale info unspecified. $locale = Locale::getLocale(); $localeFile = Locale::getMainLocaleFilename($locale); $sysLocale = $locale . '.' . LOCALE_ENCODING; if (!@setlocale(LC_ALL, $sysLocale, $locale)) { // For PHP < 4.3.0 if(setlocale(LC_ALL, $sysLocale) != $sysLocale) { setlocale(LC_ALL, $locale); } } Locale::registerLocaleFile($locale, $localeFile); } /** * Register a locale file against the current list. * @param $locale string Locale key * @param $filename string Filename to new locale XML file * @param $addToTop boolean Whether to add to the top of the list (true) * or the bottom (false). Allows overriding. */ function ®isterLocaleFile ($locale, $filename, $addToTop = false) { $localeFiles =& Locale::getLocaleFiles($locale); $localeFile =& new LocaleFile($locale, $filename); if (!$localeFile->isValid()) { $localeFile = null; return $localeFile; } if ($addToTop) { // Work-around: unshift by reference. array_unshift($localeFiles, ''); $localeFiles[0] =& $localeFile; } else { $localeFiles[] =& $localeFile; } return $localeFile; } /** * Get all supported locales for the current context. * @return array */ function getSupportedLocales() { static $supportedLocales; if (!isset($supportedLocales)) { if (defined('SESSION_DISABLE_INIT') || !Config::getVar('general', 'installed')) { $supportedLocales = Locale::getAllLocales(); } elseif (($conference =& Request::getConference())) { $supportedLocales = $conference->getSupportedLocaleNames(); } else { $site =& Request::getSite(); $supportedLocales = $site->getSupportedLocaleNames(); } } return $supportedLocales; } /** * Return the key name of the user's currently selected locale (default * is "en_US" for U.S. English). * @return string */ function getLocale() { static $currentLocale; if (!isset($currentLocale)) { if (defined('SESSION_DISABLE_INIT') || !Config::getVar('general', 'installed')) { // If the locale is specified in the URL, allow // it to override. (Necessary when locale is // being set, as cookie will not yet be re-set) $locale = Request::getUserVar('setLocale'); if (empty($locale) || !in_array($locale, Locale::getSupportedLocales())) $locale = Request::getCookieVar('currentLocale'); } else { $sessionManager = &SessionManager::getManager(); $session = &$sessionManager->getUserSession(); $locale = $session->getSessionVar('currentLocale'); $conference = &Request::getConference(); $site = &Request::getSite(); if (!isset($locale)) { $locale = Request::getCookieVar('currentLocale'); } if (isset($locale)) { // Check if user-specified locale is supported if ($conference != null) { $locales = &$conference->getSupportedLocaleNames(); } else { $locales = &$site->getSupportedLocaleNames(); } if (!in_array($locale, array_keys($locales))) { unset($locale); } } if (!isset($locale)) { // Use conference/site default if ($conference != null) { $locale = $conference->getPrimaryLocale(); } if (!isset($locale)) { $locale = $site->getPrimaryLocale(); } } } if (!Locale::isLocaleValid($locale)) { $locale = LOCALE_DEFAULT; } $currentLocale = $locale; } return $currentLocale; } function getLocaleStyleSheet($locale) { $allLocales =& Locale::_getAllLocalesCache(); $contents = $allLocales->getContents(); if (isset($contents[$locale]['stylesheet'])) { return $contents[$locale]['stylesheet']; } return null; } /** * Check if the supplied locale is currently installable. * @param $locale string * @return boolean */ function isLocaleValid($locale) { if (empty($locale)) return false; if (!preg_match('/^[a-z][a-z]_[A-Z][A-Z]$/', $locale)) return false; if (file_exists(Locale::getMainLocaleFilename($locale))) return true; return false; } /** * Get the stack of "important" locales, most important first. * @return array */ function getLocalePrecedence() { static $localePrecedence; if (!isset($localePrecedence)) { $localePrecedence = array(Locale::getLocale()); $conference =& Request::getConference(); if ($conference && !in_array($conference->getPrimaryLocale(), $localePrecedence)) $localePrecedence[] = $conference->getPrimaryLocale(); $site =& Request::getSite(); if ($site && !in_array($site->getPrimaryLocale(), $localePrecedence)) $localePrecedence[] = $site->getPrimaryLocale(); } return $localePrecedence; } /** * Retrieve the primary locale of the current context. * @return string */ function getPrimaryLocale() { $conference = &Request::getConference(); if (isset($conference)) { $locale = $conference->getPrimaryLocale(); } if (!isset($locale)) { $site = &Request::getSite(); $locale = $site->getPrimaryLocale(); } if (!isset($locale) || !Locale::isLocaleValid($locale)) { $locale = LOCALE_DEFAULT; } return $locale; } /** * Get the cache object for the current list of all locales. */ function &_getAllLocalesCache() { static $cache; if (!isset($cache)) { import('cache.CacheManager'); $cacheManager =& CacheManager::getManager(); $cache = $cacheManager->getFileCache( 'locale', 'list', array('Locale', '_allLocalesCacheMiss') ); // Check to see if the data is outdated $cacheTime = $cache->getCacheTime(); if ($cacheTime !== null && $cacheTime < filemtime(LOCALE_REGISTRY_FILE)) { $cache->flush(); } } return $cache; } function _allLocalesCacheMiss(&$cache, $id) { static $allLocales; if (!isset($allLocales)) { // Add a locale load to the debug notes. $notes =& Registry::get('system.debug.notes'); $notes[] = array('debug.notes.localeListLoad', array('localeList' => LOCALE_REGISTRY_FILE)); // Reload locale registry file $xmlDao = &new XMLDAO(); $data = $xmlDao->parseStruct(LOCALE_REGISTRY_FILE, array('locale')); // Build array with ($localKey => $localeName) if (isset($data['locale'])) { foreach ($data['locale'] as $localeData) { $allLocales[$localeData['attributes']['key']] = $localeData['attributes']; } } asort($allLocales); $cache->setEntireCache($allLocales); } return null; } /** * Return a list of all available locales. * @return array */ function &getAllLocales() { $cache =& Locale::_getAllLocalesCache(); $rawContents = $cache->getContents(); $allLocales = array(); foreach ($rawContents as $locale => $contents) { $allLocales[$locale] = $contents['name']; } // if client encoding is set to iso-8859-1, transcode locales from utf8 if (LOCALE_ENCODING == "iso-8859-1") { $allLocales = array_map('utf8_decode', $allLocales); } return $allLocales; } /** * Get the path and filename for the email templates data for the * given locale * @param $locale string * @return string */ function getEmailTemplateFilename($locale) { return 'dbscripts/xml/data/locale/' . $locale . '/email_templates_data.xml'; } function getFilesToInstall($locale) { return array( Locale::getEmailTemplateFilename($locale) ); } /** * Uninstall support for an existing locale. * @param $locale string */ function installLocale($locale) { // Install default locale-specific data import('db.DBDataXMLParser'); $filesToInstall = Locale::getFilesToInstall($locale); $dataXMLParser = &new DBDataXMLParser(); foreach ($filesToInstall as $fileName) { if (file_exists($fileName)) { $sql = $dataXMLParser->parseData($fileName); $dataXMLParser->executeData(); } } $dataXMLParser->destroy(); } /** * Install support for a new locale. * @param $locale string */ function uninstallLocale($locale) { // Delete locale-specific data $emailTemplateDao = &DAORegistry::getDAO('EmailTemplateDAO'); $emailTemplateDao->deleteEmailTemplatesByLocale($locale); $emailTemplateDao->deleteDefaultEmailTemplatesByLocale($locale); } /** * Reload locale-specific data. * @param $locale string */ function reloadLocale($locale) { Locale::uninstallLocale($locale); Locale::installLocale($locale); } /** * Test all locale files for the supplied locale against the supplied * reference locale, returning an array of errors. * @param $locale string Name of locale to test * @param $referenceLocale string Name of locale to test against * @return array */ function testLocale($locale, $referenceLocale) { $localeFile =& new LocaleFile($locale, Locale::getMainLocaleFilename($locale)); $referenceLocaleFile =& new LocaleFile($referenceLocale, Locale::getMainLocaleFilename($referenceLocale)); $errors = $localeFile->testLocale($referenceLocaleFile); unset($localeFile); unset($referenceLocaleFile); $plugins =& PluginRegistry::loadAllPlugins(); foreach (array_keys($plugins) as $key) { $plugin =& $plugins[$key]; $referenceLocaleFilename = $plugin->getLocaleFilename($referenceLocale); if ($referenceLocaleFilename) { $localeFile =& new LocaleFile($locale, $plugin->getLocaleFilename($locale)); $referenceLocaleFile =& new LocaleFile($referenceLocale, $referenceLocaleFilename); $errors = array_merge_recursive($errors, $localeFile->testLocale($referenceLocaleFile)); unset($localeFile); unset($referenceLocaleFile); } unset($plugin); } return $errors; } /** * Test the emails in the supplied locale against those in the supplied * reference locale. * @param $locale string * @param $referenceLocale string * @return array List of errors */ function testEmails($locale, $referenceLocale) { $errors = array( ); $xmlParser =& new XMLParser(); $referenceEmails =& $xmlParser->parse(Locale::getEmailTemplateFilename($referenceLocale)); $emails =& $xmlParser->parse(Locale::getEmailTemplateFilename($locale)); $emailsTable =& $emails->getChildByName('table'); $referenceEmailsTable =& $referenceEmails->getChildByName('table'); $matchedReferenceEmails = array(); // Pass 1: For all translated emails, check that they match // against reference translations. for ($emailIndex = 0; ($email =& $emailsTable->getChildByName('row', $emailIndex)) !== null; $emailIndex++) { // Extract the fields from the email to be tested. $fields = Locale::extractFields($email); // Locate the reference email and extract its fields. for ($referenceEmailIndex = 0; ($referenceEmail =& $referenceEmailsTable->getChildByName('row', $referenceEmailIndex)) !== null; $referenceEmailIndex++) { $referenceFields = Locale::extractFields($referenceEmail); if ($referenceFields['email_key'] == $fields['email_key']) break; } // Check if a matching reference email was found. if (!isset($referenceEmail) || $referenceEmail === null) { $errors[EMAIL_ERROR_EXTRA_EMAIL][] = array( 'key' => $fields['email_key'] ); continue; } // We've successfully found a matching reference email. // Compare it against the translation. $bodyParams = Locale::getParameterNames($fields['body']); $referenceBodyParams = Locale::getParameterNames($referenceFields['body']); if ($bodyParams !== $referenceBodyParams) { $errors[EMAIL_ERROR_DIFFERING_PARAMS][] = array( 'key' => $fields['email_key'], 'mismatch' => array_diff($bodyParams, $referenceBodyParams) ); } $subjectParams = Locale::getParameterNames($fields['subject']); $referenceSubjectParams = Locale::getParameterNames($referenceFields['subject']); if ($subjectParams !== $referenceSubjectParams) { $errors[EMAIL_ERROR_DIFFERING_PARAMS][] = array( 'key' => $fields['email_key'], 'mismatch' => array_diff($subjectParams, $referenceSubjectParams) ); } $matchedReferenceEmails[] = $fields['email_key']; unset($email); unset($referenceEmail); } // Pass 2: Make sure that there are no missing translations. for ($referenceEmailIndex = 0; ($referenceEmail =& $referenceEmailsTable->getChildByName('row', $referenceEmailIndex)) !== null; $referenceEmailIndex++) { // Extract the fields from the email to be tested. $referenceFields = Locale::extractFields($referenceEmail); if (!in_array($referenceFields['email_key'], $matchedReferenceEmails)) { $errors[EMAIL_ERROR_MISSING_EMAIL][] = array( 'key' => $referenceFields['email_key'] ); } } return $errors; } /** * Given a parent XML node, extract child nodes of the following form: * some_value * ... into an associate array $array['something'] = 'some_value'; * @param $node object * @return array */ function extractFields(&$node) { $returner = array(); foreach ($node->getChildren() as $field) if ($field->getName() === 'field') { $returner[$field->getAttribute('name')] = $field->getValue(); } return $returner; } /** * Determine whether or not the lengths of the two supplied values are * "similar". * @param $reference string * @param $value string * @return boolean True if the lengths match very roughly. */ function checkLengths($reference, $value) { $referenceLength = String::strlen($reference); $length = String::strlen($value); $lengthDifference = abs($referenceLength - $length); if ($referenceLength == 0) return ($length == 0); if ($lengthDifference / $referenceLength > 1 && $lengthDifference > 10) return false; return true; } /** * Given a locale string, get the list of parameter references of the * form {$myParameterName}. * @param $source string * @return array */ function getParameterNames($source) { $matches = null; String::regexp_match_get('/({\$[^}]+})/' /* '/{\$[^}]+})/' */, $source, $matches); array_shift($matches); // Knock the top element off the array return $matches; } } ?>