/** * Create a new LanguageDropdownField * @param string $name * @param string $title * @param array $dontInclude list of languages that won't be included * @param string $translatingClass Name of the class with translated instances where to look for used languages * @param string $list Indicates the source language list. Can be either Common-English, Common-Native Locale */ function __construct($name, $title, $dontInclude = array(), $translatingClass = 'SiteTree', $list = 'Common-English') { $usedlangs = array_diff(i18n::get_existing_content_languages($translatingClass), $dontInclude); // we accept in dontInclude both language codes and names, so another diff is required $usedlangs = array_diff($usedlangs, array_flip($dontInclude)); if (isset($usedlangs[Translatable::default_lang()])) { unset($usedlangs[Translatable::default_lang()]); } if ('Common-English' == $list) { $languageList = i18n::get_common_languages(); } else { if ('Common-Native' == $list) { $languageList = i18n::get_common_languages(true); } else { $languageList = i18n::get_locale_list(); } } $alllangs = array_diff($languageList, (array) $usedlangs, $dontInclude); $alllangs = array_flip(array_diff(array_flip($alllangs), $dontInclude)); if (isset($alllangs[Translatable::default_lang()])) { unset($alllangs[Translatable::default_lang()]); } asort($alllangs); if (count($usedlangs)) { asort($usedlangs); $labelAvail = _t('Form.LANGAVAIL', "Available languages"); $labelOther = _t('Form.LANGAOTHER', "Other languages"); parent::__construct($name, $title, array($labelAvail => $usedlangs, $labelOther => $alllangs), reset($usedlangs)); } else { parent::__construct($name, $title, $alllangs); } }
/** * Handles enabling translations for controllers that are not pages */ public function onBeforeInit() { //Bail for the root url controller and model as controller classes as they handle this internally, also disable for development admin and cms if ($this->owner instanceof MultilingualRootURLController || $this->owner instanceof MultilingualModelAsController || $this->owner instanceof LeftAndMain || $this->owner instanceof DevelopmentAdmin || $this->owner instanceof TestRunner) { return; } //Bail for pages since this would have been handled by MultilingualModelAsController, we're assuming that data has not been set to a page by other code if (method_exists($this->owner, 'data') && $this->owner->data() instanceof SiteTree) { return; } //Check if the locale is in the url $request = $this->owner->getRequest(); if ($request && $request->param('Language')) { $language = $request->param('Language'); if (Config::inst()->get('MultilingualRootURLController', 'UseLocaleURL')) { $locale = $language; } else { if (strpos($request->param('Language'), '_') !== false) { //Invalid format so redirect to the default $url = $request->getURL(true); $default = Config::inst()->get('MultilingualRootURLController', 'UseLocaleURL') ? Translatable::default_locale() : Translatable::default_lang(); $this->owner->redirect(preg_replace('/^' . preg_quote($language, '/') . '\\//', $default . '/', $url), 301); return; } else { $locale = i18n::get_locale_from_lang($language); } } if (in_array($locale, Translatable::get_allowed_locales())) { //Set the language cookie Cookie::set('language', $language); //Set the various locales Translatable::set_current_locale($locale); i18n::set_locale($locale); } else { //Unknown language so redirect to the default $url = $request->getURL(true); $default = Config::inst()->get('MultilingualRootURLController', 'UseLocaleURL') ? Translatable::default_locale() : Translatable::default_lang(); $this->owner->redirect(preg_replace('/^' . preg_quote($language, '/') . '\\//', $default . '/', $url), 301); } return; } //Detect the locale if ($locale = MultilingualRootURLController::detect_browser_locale()) { if (Config::inst()->get('MultilingualRootURLController', 'UseLocaleURL')) { $language = $locale; } else { $language = i18n::get_lang_from_locale($locale); } //Set the language cookie Cookie::set('language', $language); //Set the various locales Translatable::set_current_locale($locale); i18n::set_locale($locale); } }
function setUp() { $this->origTranslatableSettings['enabled'] = Translatable::is_enabled(); $this->origTranslatableSettings['default_lang'] = Translatable::default_lang(); Translatable::enable(); Translatable::set_default_lang("en"); // needs to recreate the database schema with *_lang tables self::kill_temp_db(); self::create_temp_db(); parent::setUp(); }
function run($request) { $ids = array(); echo "#################################\n"; echo "# Adding translation groups to existing records" . "\n"; echo "#################################\n"; $allSiteTreeIDs = DB::query('SELECT `ID` FROM `SiteTree`')->column(); if ($allSiteTreeIDs) { foreach ($allSiteTreeIDs as $id) { $original = DataObject::get_by_id('SiteTree', $id); $existingGroupID = $original->getTranslationGroup(); if (!$existingGroupID) { $original->addTranslationGroup($original->ID); } $original->destroy(); unset($original); } } DataObject::flush_and_destroy_cache(); echo sprintf("Created translation groups for %d records\n", count($allSiteTreeIDs)); foreach (array('Stage', 'Live') as $stage) { echo "\n\n#################################\n"; echo "# Migrating stage {$stage}" . "\n"; echo "#################################\n"; $suffix = $stage == 'Live' ? '_Live' : ''; // First get all entries in SiteTree_lang // This should be all translated pages $trans = DB::query(sprintf('SELECT * FROM `_obsolete_SiteTree_lang%s`', $suffix)); // Iterate over each translated pages foreach ($trans as $oldtrans) { $newLocale = i18n::get_locale_from_lang($oldtrans['Lang']); echo sprintf("Migrating from %s to %s translation of '%s' (#%d)\n", $oldtrans['Lang'], $newLocale, Convert::raw2xml($oldtrans['Title']), $oldtrans['OriginalLangID']); // Get the untranslated page $original = Versioned::get_one_by_stage($oldtrans['ClassName'], $stage, '`SiteTree`.`ID` = ' . $oldtrans['OriginalLangID']); if (!$original) { echo sprintf("Couldn't find original for #%d", $oldtrans['OriginalLangID']); continue; } // write locale to $original $original->Locale = i18n::get_locale_from_lang(Translatable::default_lang()); $original->writeToStage($stage); // Clone the original, and set it up as a translation $existingTrans = $original->getTranslation($newLocale, $stage); if ($existingTrans) { echo sprintf("Found existing new-style translation for #%d. Already merged? Skipping.\n", $oldtrans['OriginalLangID']); continue; } // Doesn't work with stage/live split //$newtrans = $original->createTranslation($newLocale); $newtrans = $original->duplicate(false); $newtrans->OriginalID = $original->ID; // we have to "guess" a locale based on the language $newtrans->Locale = $newLocale; if ($stage == 'Live' && array_key_exists($original->ID, $ids)) { $newtrans->ID = $ids[$original->ID]; } // Look at each class in the ancestry, and see if there is a _lang table for it foreach (ClassInfo::ancestry($oldtrans['ClassName']) as $classname) { $oldtransitem = false; // If the class is SiteTree, we already have the DB record, else check for the table and get the record if ($classname == 'SiteTree') { $oldtransitem = $oldtrans; } elseif (in_array(strtolower($classname) . '_lang', DB::tableList())) { $oldtransitem = DB::query(sprintf('SELECT * FROM `_obsolete_%s_lang%s` WHERE `OriginalLangID` = %d AND `Lang` = \'%s\'', $classname, $suffix, $original->ID, $oldtrans['Lang']))->first(); } // Copy each translated field into the new translation if ($oldtransitem) { foreach ($oldtransitem as $key => $value) { if (!in_array($key, array('ID', 'OriginalLangID'))) { $newtrans->{$key} = $value; } } } } // Write the new translation to the database $sitelang = Translatable::get_current_locale(); Translatable::set_current_locale($newtrans->Locale); $newtrans->writeToStage($stage); Translatable::set_current_locale($sitelang); $newtrans->addTranslationGroup($original->getTranslationGroup(), true); if ($stage == 'Stage') { $ids[$original->ID] = $newtrans->ID; } } } echo "\n\n#################################\n"; echo "Done!\n"; }
/** * Get default language (proxy for Translatable::default_lang()) * * @return String */ static function default_lang() { return Translatable::default_lang(); }
/** * Set default language. * * @param $lang String */ static function set_default_lang($lang) { self::$default_lang = $lang; }
public function handleRequest(SS_HTTPRequest $request, DataModel $model = null) { self::$is_at_root = true; $this->setDataModel($model); $this->pushCurrent(); $this->init(); if ($language = $request->param('Language')) { if (Config::inst()->get('MultilingualRootURLController', 'UseLocaleURL')) { if (Config::inst()->get('MultilingualRootURLController', 'UseDashLocale')) { //Language is missing a dash 404 if (strpos($language, '-') === false) { //Locale not found 404 if ($response = ErrorPage::response_for(404)) { return $response; } else { $this->httpError(404, 'The requested page could not be found.'); } return $this->response; } $locale = explode('-', $language); $locale[1] = strtoupper($locale[1]); //Make sure that the language is all lowercase if ($language == implode('-', $locale)) { //Locale not found 404 if ($response = ErrorPage::response_for(404)) { return $response; } else { $this->httpError(404, 'The requested page could not be found.'); } return $this->response; } $locale = implode('_', $locale); } else { $locale = $language; } } else { if (strpos($request->param('Language'), '_') !== false) { //Locale not found 404 if ($response = ErrorPage::response_for(404)) { return $response; } else { $this->httpError(404, 'The requested page could not be found.'); } return $this->response; } else { $locale = i18n::get_locale_from_lang($language); } } if (in_array($locale, Translatable::get_allowed_locales())) { Cookie::set('language', $language); Translatable::set_current_locale($locale); i18n::set_locale($locale); if (!DB::isActive() || !ClassInfo::hasTable('SiteTree')) { $this->response = new SS_HTTPResponse(); $this->response->redirect(Director::absoluteBaseURL() . 'dev/build?returnURL=' . (isset($_GET['url']) ? urlencode($_GET['url']) : null)); return $this->response; } $request->setUrl($language . '/' . self::get_homepage_link() . '/'); $request->match('$Language/$URLSegment//$Action', true); $controller = new MultilingualModelAsController(); $result = $controller->handleRequest($request, $model); $this->popCurrent(); return $result; } else { //URL Param Locale is not allowed so redirect to default $this->redirect(Controller::join_links(Director::baseURL(), Config::inst()->get('MultilingualRootURLController', 'UseLocaleURL') ? Translatable::default_locale() : Translatable::default_lang()) . '/', 301); $this->popCurrent(); return $this->response; } } //No Locale Param so detect browser language and redirect if ($locale = self::detect_browser_locale()) { if (Config::inst()->get('MultilingualRootURLController', 'UseLocaleURL')) { if (Config::inst()->get('MultilingualRootURLController', 'UseDashLocale')) { $language = str_replace('_', '-', strtolower($locale)); } else { $language = $locale; } } else { $language = i18n::get_lang_from_locale($locale); } Cookie::set('language', $language); $this->redirect(Controller::join_links(Director::baseURL(), $language) . '/', 301); $this->popCurrent(); return $this->response; } if (Config::inst()->get('MultilingualRootURLController', 'UseLocaleURL')) { if (Config::inst()->get('MultilingualRootURLController', 'UseDashLocale')) { $language = str_replace('_', '-', strtolower(Translatable::default_locale())); } else { $language = Translatable::default_locale(); } } else { $language = Translatable::default_lang(); } $this->redirect(Controller::join_links(Director::baseURL(), $language . '/'), 301); $this->popCurrent(); return $this->response; }
/** * Switch the cms language and reload the site tree * */ function switchlanguage($lang, $donotcreate = null) { //is it's a clean switch (to an existing language deselect the current page) if (is_string($lang)) { $dontunloadPage = true; } $lang = is_string($lang) ? $lang : urldecode($this->urlParams['ID']); if ($lang != Translatable::default_lang()) { Translatable::set_reading_lang(Translatable::default_lang()); $tree_class = $this->stat('tree_class'); $obj = new $tree_class(); $allIDs = $obj->getDescendantIDList(); $allChildren = $obj->AllChildren(); $classesMap = $allChildren->map('ID', 'ClassName'); $titlesMap = $allChildren->map(); Translatable::set_reading_lang($lang); $obj = new $tree_class(); $languageIDs = $obj->getDescendantIDList(); $notcreatedlist = array_diff($allIDs, $languageIDs); FormResponse::add("\$('addpage').getElementsByTagName('button')[0].disabled=true;"); FormResponse::add("\$('Form_AddPageOptionsForm').getElementsByTagName('div')[1].getElementsByTagName('input')[0].disabled=true;"); FormResponse::add("\$('Translating_Message').innerHTML = 'Translating mode - " . i18n::get_language_name($lang) . "';"); FormResponse::add("Element.removeClassName('Translating_Message','nonTranslating');"); } else { Translatable::set_reading_lang($lang); FormResponse::add("\$('addpage').getElementsByTagName('button')[0].disabled=false;"); FormResponse::add("\$('Form_AddPageOptionsForm').getElementsByTagName('div')[1].getElementsByTagName('input')[0].disabled=false;"); FormResponse::add("Element.addClassName('Translating_Message','nonTranslating');"); } $obj = singleton($this->stat('tree_class')); $obj->markPartialTree(); $siteTree = $obj->getChildrenAsUL("", ' "<li id=\\"record-$child->ID\\" class=\\"" . $child->CMSTreeClasses($extraArg) . "\\">" . "<a href=\\"" . Director::link(substr($extraArg->Link(),0,-1), "show", $child->ID) . "\\" " . (($child->canEdit() || $child->canAddChildren()) ? "" : "class=\\"disabled\\"") . " title=\\"' . _t('LeftAndMain.PAGETYPE') . '".$child->class."\\" >" . (Convert::raw2js($child->TreeTitle())) . "</a>" ', $this, true); $rootLink = $this->Link() . '0'; $siteTree = "<li id=\"record-0\" class=\"Root nodelete\"><a href=\"{$rootLink}\">" . _t('LeftAndMain.SITECONTENT') . "</a>" . $siteTree . "</li></ul>"; FormResponse::add("\$('sitetree').innerHTML ='" . ereg_replace("[\n]", "\\\n", $siteTree) . "';"); FormResponse::add("SiteTree.applyTo('#sitetree');"); if (isset($notcreatedlist)) { foreach ($notcreatedlist as $notcreated) { if ($notcreated == $donotcreate) { continue; } $id = "new-{$classesMap[$notcreated]}-0-{$notcreated}"; Session::set($id . '_originalLangID', $notcreated); $treeTitle = Convert::raw2js($titlesMap[$notcreated]); $response = <<<JS \t\t\t\t\tvar tree = \$('sitetree'); \t\t\t\t\tvar newNode = tree.createTreeNode("{$id}", "{$treeTitle}", "{$classesMap[$notcreated]} (untranslated)"); \t\t\t\t\taddClass(newNode, 'untranslated'); \t\t\t\t\tnode = tree.getTreeNodeByIdx(0); \t\t\t\t\tnode.open(); \t\t\t\t\tnode.appendTreeNode(newNode); JS; FormResponse::add($response); } } if (!isset($dontunloadPage)) { FormResponse::add("node = \$('sitetree').getTreeNodeByIdx(0); node.selectTreeNode();"); } return FormResponse::respond(); }
/** * Get a list of languages with at least one element translated in (including the default language) * * @param string $className Look for languages in elements of this class * @return array Map of languages in the form langCode => langName */ static function get_existing_content_languages($className = 'SiteTree', $where = '') { if(!Translatable::is_enabled()) return false; $baseTable = ClassInfo::baseDataClass($className); $query = new SQLQuery('Lang',$baseTable.'_lang',$where,"",'Lang'); $dbLangs = $query->execute()->column(); $langlist = array_merge((array)Translatable::default_lang(), (array)$dbLangs); $returnMap = array(); $allCodes = array_merge(i18n::$all_locales, i18n::$common_languages); foreach ($langlist as $langCode) { if($langCode) $returnMap[$langCode] = (is_array($allCodes[$langCode]) ? $allCodes[$langCode][0] : $allCodes[$langCode]); } return $returnMap; }