/**
  * 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);
     }
 }
 /**
  * Try very hard to get a locale for this user. Helps for i18n etc.
  * @return string
  */
 public static function get_smart_locale($language = null)
 {
     require_once FRAMEWORK_PATH . '/thirdparty/Zend/Locale.php';
     $locale = Zend_Locale::getBrowser();
     if (!$locale) {
         if ($language) {
             return i18n::get_locale_from_lang($language);
         } else {
             return i18n::get_locale();
         }
     }
     $locale = array_keys($locale);
     $firstPref = array_shift($locale);
     if (strpos($firstPref, '_') === false) {
         return i18n::get_locale_from_lang($language);
     }
     return $firstPref;
 }
 /**
  * For field types that can contain a variety of data, e.g. Varchar, this method
  * informs the Faker\Generator object what kind of data to generate based on the name of the field.
  * For instance, a field named "FirstName" should generate a person's name. A field named "Country" should
  * generate a country name.
  *
  * Field names can be matched at the beginning or end of the string, for instance:
  * "DoctorFirstName" and "Address2" will generate a first name and an address, respectively.
  *
  * This logic can be refined in the lang file so that database fields can be named in the local language,
  * e.g. "Prenom" or "Pays" and still be mapped to the correct data type.
  *
  * @param string $name The name of the data type to examine
  * @return boolean
  */
 public function hook($name)
 {
     $list = false;
     $current_locale = i18n::get_locale();
     $default_lang = Config::inst()->forClass("MockDBField")->default_lang;
     $default_locale = i18n::get_locale_from_lang($default_lang);
     i18n::set_locale($default_locale);
     $core_list = _t('MockDataObject.' . $name);
     i18n::set_locale($current_locale);
     $user_list = _t('MockDataObject.' . $name);
     $list = $user_list ?: $core_list;
     if ($list) {
         $candidates = explode(",", $list);
         $fieldName = $this->owner->getName();
         foreach ($candidates as $c) {
             $c = trim($c);
             if (preg_match('/^' . $c . '[A-Z0-9]*/', $fieldName) || preg_match('/' . $c . '$/', $fieldName)) {
                 return true;
             }
         }
     }
     return false;
 }
 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";
 }
 public function testGetLocaleFromLang()
 {
     $this->assertEquals('en_US', i18n::get_locale_from_lang('en'));
     $this->assertEquals('de_DE', i18n::get_locale_from_lang('de_DE'));
     $this->assertEquals('xy_XY', i18n::get_locale_from_lang('xy'));
 }
Example #6
0
 /**
  * @deprecated 2.4 Use get_one_by_locale()
  */
 static function get_one_by_lang($class, $lang, $filter = '', $cache = false, $orderby = "")
 {
     return self::get_one_by_locale($class, i18n::get_locale_from_lang($lang), $filter, $cache, $orderby);
 }
 /**
  * Determines the locale best matching the given list of browser locales
  * @return {string} The matching locale, or null if none could be determined
  */
 public static function detect_browser_locale()
 {
     if ($language = Cookie::get('language')) {
         if (Config::inst()->get('MultilingualRootURLController', 'UseLocaleURL')) {
             $locale = $language;
         } else {
             $locale = i18n::get_locale_from_lang($language);
         }
         if (in_array($locale, Translatable::get_allowed_locales())) {
             return $locale;
         } else {
             Cookie::force_expiry('language');
         }
     }
     // Given multiple canditates, narrow down the final result using the client's preferred languages
     $inputLocales = array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : null;
     if (empty($inputLocales)) {
         return null;
     }
     // Generate mapping of priority => list of languages at this priority
     // break up string into pieces (languages and q factors)
     preg_match_all('/(?<code>[a-z]{1,8}(-[a-z]{1,8})?)\\s*(;\\s*q\\s*=\\s*(?<priority>1|0\\.[0-9]+))?/i', $inputLocales, $parsedLocales);
     $prioritisedLocales = array();
     if (count($parsedLocales['code'])) {
         // create a list like "en" => 0.8
         $parsedLocales = array_combine($parsedLocales['code'], $parsedLocales['priority']);
         // Generate nested list of priorities => [languages]
         foreach ($parsedLocales as $language => $priority) {
             $priority = empty($priority) ? 1.0 : floatval($priority);
             if (empty($prioritisedLocales[$priority])) {
                 $prioritisedLocales[$priority] = array();
             }
             $prioritisedLocales[$priority][] = $language;
         }
         // sort list based on value
         krsort($prioritisedLocales, SORT_NUMERIC);
     }
     // Check each requested language against loaded languages
     foreach ($prioritisedLocales as $priority => $parsedLocales) {
         foreach ($parsedLocales as $browserLocale) {
             foreach (Translatable::get_allowed_locales() as $language) {
                 if (stripos(preg_replace('/_/', '-', $language), $browserLocale) === 0) {
                     return $language;
                 }
             }
         }
     }
     return null;
 }
    $country->ISO3 = "ZWE";
    $country->FIPS = "ZI";
    $country->ISON = "716";
    $country->Title = _t("SilvercartCountry.TITLE_ZW");
    $country->Continent = "AF";
    $country->Currency = "ZWL";
    $country->Locale = Translatable::get_current_locale();
    $country->write();
}
$translatorsByPrio = i18n::get_translators();
foreach ($translatorsByPrio as $priority => $translators) {
    foreach ($translators as $name => $translator) {
        $adapter = $translator->getAdapter();
        $languages = $adapter->getList();
        foreach ($languages as $language) {
            $locale = i18n::get_locale_from_lang($language);
            if ($country->hasLanguage($locale)) {
                continue;
            }
            $data = $adapter->getMessages($language);
            foreach (SilvercartCountry::get() as $country) {
                $key = 'TITLE_' . strtoupper($country->ISO2);
                if (array_key_exists('SilvercartCountry.' . $key, $data)) {
                    $translation = new SilvercartCountryLanguage();
                    $translation->Locale = $locale;
                    $translation->Title = $data['SilvercartCountry.' . $key];
                    $translation->write();
                    $country->SilvercartCountryLanguages()->add($translation);
                }
            }
        }
 public function run($request)
 {
     echo 'Run with ?clear=1 to clear empty database before running the task<br/>';
     echo 'Run with ?overwrite=soft|hard to overwrite templates that exists in the cms. Soft will replace template if not modified by the user, hard will replace template even if modified by user.<br/>';
     echo 'Run with ?templates=xxx,yyy to specify which template should be imported<br/>';
     echo 'Run with ?subsite=all|subsiteID to create email templates in all subsites (including main site) or only in the chosen subsite (if a subsite is active, it will be used by default).<br/>';
     echo 'Run with ?locales=fr,en to choose which locale to import.<br/>';
     echo '<strong>Remember to flush the templates/translations if needed</strong><br/>';
     echo '<hr/>';
     $overwrite = $request->getVar('overwrite');
     $clear = $request->getVar('clear');
     $templatesToImport = $request->getVar('templates');
     $importToSubsite = $request->getVar('subsite');
     $chosenLocales = $request->getVar('locales');
     // Normalize argument
     if ($overwrite && $overwrite != 'soft' && $overwrite != 'hard') {
         $overwrite = 'soft';
     }
     $subsites = array();
     if ($importToSubsite == 'all') {
         $subsites = Subsite::get()->map();
     } else {
         if (is_numeric($importToSubsite)) {
             $subsites = array($importToSubsite => Subsite::get()->byID($importToSubsite)->Title);
         }
     }
     if (class_exists('Subsite') && Subsite::currentSubsiteID()) {
         DB::alteration_message("Importing to current subsite. Run from main site to import other subsites at once.", "created");
         $subsites = array();
     }
     if (!empty($subsites)) {
         DB::alteration_message("Importing to subsites : " . implode(',', array_values($subsites)), "created");
     }
     if ($templatesToImport) {
         $templatesToImport = explode(',', $templatesToImport);
     }
     if ($clear == 1) {
         DB::alteration_message("Clear all email templates", "created");
         $emailTemplates = EmailTemplate::get();
         foreach ($emailTemplates as $emailTemplate) {
             $emailTemplate->delete();
         }
     }
     $emailTemplateSingl = singleton('EmailTemplate');
     $ignoredModules = self::config()->ignored_modules;
     if (!is_array($ignoredModules)) {
         $ignoredModules = array();
     }
     $locales = null;
     if (class_exists('Fluent') && Fluent::locale_names()) {
         if ($emailTemplateSingl->hasExtension('FluentExtension')) {
             $locales = array_keys(Fluent::locale_names());
             if ($chosenLocales) {
                 $arr = explode(',', $chosenLocales);
                 $locales = array();
                 foreach ($arr as $a) {
                     if (strlen($a) == 2) {
                         $a = i18n::get_locale_from_lang($a);
                     }
                     $locales[] = $a;
                 }
             }
         }
     }
     $defaultLocale = i18n::get_locale();
     $templates = SS_TemplateLoader::instance()->getManifest()->getTemplates();
     foreach ($templates as $t) {
         $isOverwritten = false;
         // Emails in mysite/email are not properly marked as emails
         if (isset($t['mysite']) && isset($t['mysite']['email'])) {
             $t['email'] = $t['mysite']['email'];
         }
         // Should be in the /email folder
         if (!isset($t['email'])) {
             continue;
         }
         $filePath = $t['email'];
         $fileName = basename($filePath, '.ss');
         // Should end with *Email
         if (!preg_match('/Email$/', $fileName)) {
             continue;
         }
         $relativeFilePath = str_replace(Director::baseFolder(), '', $filePath);
         $relativeFilePathParts = explode('/', trim($relativeFilePath, '/'));
         // Group by module
         $module = array_shift($relativeFilePathParts);
         // Ignore some modules
         if (in_array($module, $ignoredModules)) {
             continue;
         }
         array_shift($relativeFilePathParts);
         // remove /templates part
         $templateName = str_replace('.ss', '', implode('/', $relativeFilePathParts));
         $templateTitle = basename($templateName);
         // Create a default code from template name
         $code = strtolower(preg_replace('/([a-zA-Z])(?=[A-Z])/', '$1-', $fileName));
         $code = preg_replace('/-email$/', '', $code);
         if (!empty($templatesToImport) && !in_array($code, $templatesToImport)) {
             DB::alteration_message("Template with code <b>{$code}</b> was ignored.", "repaired");
             continue;
         }
         $whereCode = array('Code' => $code);
         $emailTemplate = EmailTemplate::get()->filter($whereCode)->first();
         // Check if it has been modified or not
         $templateModified = false;
         if ($emailTemplate) {
             $templateModified = $emailTemplate->Created != $emailTemplate->LastEdited;
         }
         if (!$overwrite && $emailTemplate) {
             DB::alteration_message("Template with code <b>{$code}</b> already exists. Choose overwrite if you want to import again.", "repaired");
             continue;
         }
         if ($overwrite == 'soft' && $templateModified) {
             DB::alteration_message("Template with code <b>{$code}</b> has been modified by the user. Choose overwrite=hard to change.", "repaired");
             continue;
         }
         // Create a default title from code
         $title = explode('-', $code);
         $title = array_map(function ($item) {
             return ucfirst($item);
         }, $title);
         $title = implode(' ', $title);
         // Get content of the email
         $content = file_get_contents($filePath);
         // Analyze content to find incompatibilities
         $errors = array();
         if (strpos($content, '<% with') !== false) {
             $errors[] = 'Replace "with" blocks by plain calls to the variable';
         }
         if (strpos($content, '<% if') !== false) {
             $errors[] = 'If/else logic is not supported. Please create one template by use case or abstract logic into the model';
         }
         if (strpos($content, '<% loop') !== false) {
             $errors[] = 'Loops are not supported. Please create a helper method on the model to render the loop';
         }
         if (strpos($content, '<% sprintf') !== false) {
             $errors[] = 'You should not use sprintf to escape content, please use plain _t calls';
         }
         if (!empty($errors)) {
             echo "<div style='color:red'>Invalid syntax was found in '{$relativeFilePath}'. Please fix these errors before importing the template<ul>";
             foreach ($errors as $error) {
                 echo '<li>' . $error . '</li>';
             }
             echo '</ul></div>';
             continue;
         }
         // Parse language
         $collector = new i18nTextCollector();
         $entities = $collector->collectFromTemplate($content, $fileName, $module);
         $translationTable = array();
         foreach ($entities as $entity => $data) {
             if ($locales) {
                 foreach ($locales as $locale) {
                     i18n::set_locale($locale);
                     if (!isset($translationTable[$entity])) {
                         $translationTable[$entity] = array();
                     }
                     $translationTable[$entity][$locale] = i18n::_t($entity);
                 }
                 i18n::set_locale($defaultLocale);
             } else {
                 $translationTable[$entity] = array($defaultLocale => i18n::_t($entity));
             }
         }
         $contentLocale = array();
         foreach ($locales as $locale) {
             $contentLocale[$locale] = $content;
         }
         foreach ($translationTable as $entity => $translationData) {
             $escapedEntity = str_replace('.', '\\.', $entity);
             $baseTranslation = null;
             foreach ($translationData as $locale => $translation) {
                 if (!$baseTranslation && $translation) {
                     $baseTranslation = $translation;
                 }
                 if (!$translation) {
                     $translation = $baseTranslation;
                 }
                 // This regex should match old and new style
                 $count = 0;
                 $contentLocale[$locale] = preg_replace("/<%(t | _t\\(')" . $escapedEntity . "( |').*?%>/ums", $translation, $contentLocale[$locale], -1, $count);
                 if (!$count) {
                     throw new Exception("Failed to replace {$escapedEntity} with translation {$translation}");
                 }
             }
         }
         if (!$emailTemplate) {
             $emailTemplate = new EmailTemplate();
         } else {
             $isOverwritten = true;
         }
         // Scan for extra models based on convention
         preg_match_all('/\\$([a-zA-Z]+)\\./ms', $contentLocale[$defaultLocale], $matches);
         $extraModels = array();
         if (!empty($matches) && !empty($matches[1])) {
             $arr = array_unique($matches[1]);
             foreach ($arr as $n) {
                 if (strtolower($n) === 'siteconfig') {
                     continue;
                 }
                 if (class_exists($n)) {
                     $extraModels[$n] = $n;
                 }
             }
         }
         // Apply content to email
         $this->assignContent($emailTemplate, $contentLocale[$defaultLocale]);
         if (!empty($locales)) {
             foreach ($locales as $locale) {
                 $this->assignContent($emailTemplate, $contentLocale[$locale], $locale);
             }
         }
         // Title
         $emailTemplate->Title = $title;
         if (!empty($locales)) {
             // By convention, we store the translation under NameOfTheTemplateEmail.SUBJECT
             foreach ($locales as $locale) {
                 i18n::set_locale($locale);
                 $localeField = 'Title_' . $locale;
                 $entity = $templateTitle . '.SUBJECT';
                 $translation = i18n::_t($entity);
                 if (!$translation) {
                     $translation = $title;
                     DB::alteration_message("No title found in {$locale} for {$title}. You should define {$templateTitle}.SUBJECT", "error");
                 }
                 $emailTemplate->{$localeField} = $translation;
                 if (strpos($translation, '%s') !== false) {
                     echo '<div style="color:red">There is a %s in the title that should be replaced in locale ' . $locale . '!</div>';
                 }
                 if ($locale == $defaultLocale) {
                     $emailTemplate->Title = $translation;
                 }
             }
             i18n::set_locale($defaultLocale);
         }
         // Other properties
         $emailTemplate->Code = $code;
         $emailTemplate->Category = $module;
         if (class_exists('Subsite') && Subsite::currentSubsiteID()) {
             $emailTemplate->SubsiteID = Subsite::currentSubsiteID();
         }
         $emailTemplate->setExtraModelsAsArray($extraModels);
         // Write to main site or current subsite
         $emailTemplate->write();
         $this->resetLastEditedDate($emailTemplate->ID);
         // Loop through subsites
         if (!empty($importToSubsite)) {
             Subsite::$disable_subsite_filter = true;
             foreach ($subsites as $subsiteID => $subsiteTitle) {
                 $whereCode['SubsiteID'] = $subsiteID;
                 $subsiteEmailTemplate = EmailTemplate::get()->filter($whereCode)->first();
                 $emailTemplateCopy = $emailTemplate;
                 $emailTemplateCopy->SubsiteID = $subsiteID;
                 if ($subsiteEmailTemplate) {
                     $emailTemplateCopy->ID = $subsiteEmailTemplate->ID;
                 } else {
                     $emailTemplateCopy->ID = 0;
                     // New
                 }
                 $emailTemplateCopy->write();
                 $this->resetLastEditedDate($emailTemplateCopy->ID);
             }
         }
         if ($isOverwritten) {
             DB::alteration_message("Overwrote <b>{$emailTemplate->Code}</b>", "created");
         } else {
             DB::alteration_message("Imported <b>{$emailTemplate->Code}</b>", "created");
         }
     }
 }
Example #10
0
 /**
  * Switch to another subsite through storing the subsite identifier in the current PHP session.
  * Only takes effect when {@link Subsite::$use_session_subsiteid} is set to TRUE.
  *
  * @param int|Subsite $subsite Either the ID of the subsite, or the subsite object itself
  */
 public static function changeSubsite($subsite)
 {
     // Session subsite change only meaningful if the session is active.
     // Otherwise we risk setting it to wrong value, e.g. if we rely on currentSubsiteID.
     if (!Subsite::$use_session_subsiteid) {
         return;
     }
     if (is_object($subsite)) {
         $subsiteID = $subsite->ID;
     } else {
         $subsiteID = $subsite;
     }
     Session::set('SubsiteID', (int) $subsiteID);
     // Set locale
     if (is_object($subsite) && $subsite->Language != '') {
         $locale = i18n::get_locale_from_lang($subsite->Language);
         if ($locale) {
             i18n::set_locale($locale);
         }
     }
     Permission::flush_permission_cache();
 }
 /**
  */
 function translate($data, $form)
 {
     increase_time_limit_to(600);
     // Simple validation
     if (!isset($data['From']) || !$data['From']) {
         echo "Specify origin language.";
         exit;
     }
     if (!isset($data['To']) || !$data['To']) {
         echo "Specify destination language.";
         exit;
     }
     $data['From'] = i18n::get_locale_from_lang($data['From']);
     $data['To'] = i18n::get_locale_from_lang($data['To']);
     $locales = array_keys(i18n::get_locale_list());
     if (!in_array($data['From'], $locales)) {
         echo "Origin language invalid.";
         exit;
     }
     if (!in_array($data['To'], $locales)) {
         echo "Destination language invalid.";
         exit;
     }
     if ($data['From'] == $data['To']) {
         echo "Origin and destination languages are the same.";
         exit;
     }
     $mangle = false;
     if (isset($data['Mangle']) && $data['Mangle']) {
         $mangle = true;
     }
     // We want to work off Draft, because that's what's visible in the CMS.
     Versioned::reading_stage('Stage');
     Translatable::set_current_locale($data['From']);
     $pages = SiteTree::get();
     // Remove the target locale's site.
     SiteTree::get()->filter('Locale', $data['To'])->removeAll();
     foreach ($pages as $page) {
         echo "Now processing {$page->ID}<br/>\n";
         // Start from the highest parent for each page - otherwise the parents are not translated properly.
         $stack = array();
         $parent = $page;
         while ($parent && $parent->ID) {
             array_unshift($stack, $parent);
             $parent = $parent->Parent();
         }
         // We will hit the same pages multiple times, but this is an easiest way to do it and it's just a tool.
         foreach ($stack as $stackPage) {
             $translation = $stackPage->getTranslation($data['To']);
             if ($translation && $translation->ID) {
                 // Skip pages that have already been translated.
                 echo "{$stackPage->ID}: exists, skipping.<br/>\n";
             } else {
                 $translation = $stackPage->createTranslation($data['To']);
                 if ($mangle) {
                     $this->fakeTranslation($translation);
                 }
                 $translation->write();
                 echo "{$stackPage->ID}: translated.<br/>\n";
             }
         }
     }
 }
 /**
  * Adds translatable languages
  *
  * @param mixed A list of languages, either as an array or argument list 
  */
 public static function set_langs()
 {
     $args = func_get_args();
     if (empty($args)) {
         trigger_error("TranslatableDataObject::set_langs() called with no arguments.", E_USER_ERROR);
     }
     $langs = isset($args[0]) && is_array($args[0]) ? $args[0] : $args;
     foreach ($langs as $l) {
         if (!i18n::get_locale_from_lang($l)) {
             trigger_error("TranslatableDataObject::set_langs() -- Languages '{$l}' is not a valid language.", E_USER_ERROR);
         }
         self::$langs[$l] = $l;
     }
 }
 public function collect($restrictToModules = null, $mergeWithExisting = true)
 {
     $clearUnused = $this->getClearUnused();
     $glob = glob($this->basePath . '/*', GLOB_ONLYDIR);
     $modules = array_map(function ($item) {
         return basename($item);
     }, $glob);
     $themeFolders = array();
     // A master string tables array (one master per module)
     $entitiesByModule = array();
     // Scan themes
     foreach ($modules as $index => $module) {
         if ($module != 'themes') {
             continue;
         } else {
             $themes = scandir($this->basePath . "/themes");
             if (count($themes)) {
                 foreach ($themes as $theme) {
                     if (is_dir($this->basePath . "/themes/" . $theme) && substr($theme, 0, 1) != '.' && is_dir($this->basePath . "/themes/" . $theme . "/templates")) {
                         $themeFolders[] = 'themes/' . $theme;
                     }
                 }
             }
             $themesInd = $index;
         }
     }
     if (isset($themesInd)) {
         unset($modules[$themesInd]);
     }
     $modules = array_merge($modules, $themeFolders);
     foreach ($modules as $module) {
         if ($restrictToModules && !in_array($module, $restrictToModules)) {
             continue;
         }
         // Only search for calls in folder with a _config.php file (which means they are modules, including
         // themes folder)
         $isValidModuleFolder = is_dir("{$this->basePath}/{$module}") && is_file("{$this->basePath}/{$module}/_config.php") && substr($module, 0, 1) != '.' || substr($module, 0, 7) == 'themes/' && is_dir("{$this->basePath}/{$module}");
         if (!$isValidModuleFolder) {
             continue;
         }
         // we store the master string tables
         $processedEntities = $this->processModule($module);
         if (isset($entitiesByModule[$module])) {
             $entitiesByModule[$module] = array_merge_recursive($entitiesByModule[$module], $processedEntities);
         } else {
             $entitiesByModule[$module] = $processedEntities;
         }
         // extract all entities for "foreign" modules (fourth argument)
         foreach ($entitiesByModule[$module] as $fullName => $spec) {
             if (isset($spec[2]) && $spec[2] && $spec[2] != $module) {
                 $othermodule = $spec[2];
                 if (!isset($entitiesByModule[$othermodule])) {
                     $entitiesByModule[$othermodule] = array();
                 }
                 unset($spec[2]);
                 $entitiesByModule[$othermodule][$fullName] = $spec;
                 unset($entitiesByModule[$module][$fullName]);
             }
         }
         if ($mergeWithExisting) {
             $locale = $this->defaultLocale;
             // If we pass simple lang instead of locale, Zend_Translate will complain
             if (strlen($locale) == 2) {
                 if (class_exists('Fluent')) {
                     $fluentLocales = Fluent::locale_names();
                     foreach ($fluentLocales as $fluentLocale => $name) {
                         if (substr($fluentLocale, 0, 2) == $locale) {
                             $locale = $fluentLocale;
                         }
                     }
                 } else {
                     $locale = i18n::get_locale_from_lang($locale);
                 }
             }
             $adapter = Injector::inst()->create('i18nRailsYamlAdapter');
             $masterFile = "{$this->basePath}/{$module}/lang/" . $adapter->getFilenameForLocale($this->defaultLocale);
             if (!file_exists($masterFile)) {
                 continue;
             }
             $adapter->addTranslation(array('content' => $masterFile, 'locale' => $this->defaultLocale, 'reload' => true, 'clear' => true));
             //do not overwrite by interverting
             $messages = array_map(function ($v) {
                 return array($v);
             }, $adapter->getMessages($this->defaultLocale));
             $entitiesByModule[$module] = array_merge($entitiesByModule[$module], $messages);
             //clear by diffing
             if ($clearUnused) {
                 $unusedEntities = array_diff(array_keys($messages), array_keys($processedEntities));
                 foreach ($unusedEntities as $unusedEntity) {
                     if (strpos($unusedEntity, '.db_') !== false) {
                         continue;
                     }
                     if (strpos($unusedEntity, '.has_one_') !== false) {
                         continue;
                     }
                     if (strpos($unusedEntity, '.has_many_') !== false) {
                         continue;
                     }
                     if (strpos($unusedEntity, '.many_many') !== false) {
                         continue;
                     }
                     if (strpos($unusedEntity, '.belongs_many_many') !== false) {
                         continue;
                     }
                     echo '<div style="color:red">Removed translations for ' . $unusedEntity . '</div>';
                     unset($entitiesByModule[$module][$unusedEntity]);
                 }
             }
         }
     }
     // Restrict modules we update to just the specified ones (if any passed)
     if ($restrictToModules && count($restrictToModules)) {
         foreach (array_diff(array_keys($entitiesByModule), $restrictToModules) as $module) {
             unset($entitiesByModule[$module]);
         }
     }
     return $entitiesByModule;
 }
 /**
  * @uses ModelAsController::getNestedController()
  * @return SS_HTTPResponse
  */
 public function handleRequest(SS_HTTPRequest $request, DataModel $model)
 {
     $this->request = $request;
     $this->setDataModel($model);
     $this->pushCurrent();
     //Get the local from the language param
     if (Config::inst()->get('MultilingualRootURLController', 'UseLocaleURL')) {
         if (Config::inst()->get('MultilingualRootURLController', 'UseDashLocale')) {
             //Language is missing a dash 404
             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;
             }
             $locale = explode('-', $request->param('Language'));
             $locale[1] = strtoupper($locale[1]);
             //Make sure that the language is all lowercase
             if ($request->param('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 = $request->param('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($request->param('Language'));
         }
     }
     if (in_array($locale, Translatable::get_allowed_locales())) {
         //Set the current locale and remember it
         Cookie::set('language', $request->param('Language'));
         Translatable::set_current_locale($locale);
         i18n::set_locale($locale);
     } else {
         //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;
     }
     //Handle the home page for the language
     $urlSegment = $request->param('URLSegment');
     if (empty($urlSegment)) {
         $controller = new MultilingualRootURLController();
         $response = $controller->handleRequest($request, $model);
         $this->popCurrent();
         return $response;
     }
     //Normal page request so handle that
     $response = parent::handleRequest($request, $model);
     $this->popCurrent();
     return $response;
 }