diff --git a/code/model/Translatable.php b/code/model/Translatable.php index 910e251..4ebb4ec 100755 --- a/code/model/Translatable.php +++ b/code/model/Translatable.php @@ -212,15 +212,7 @@ class Translatable extends DataExtension implements PermissionProvider { * common locales. */ protected static $allowed_locales = null; - - /** - * @var array An array of fields which should be excluded from - * being transformed in the CMS for translated dataobjects. This - * includes some default excludes and any field which has already - * been transformed. - */ - protected $translatableExcludes = null; - + /** * Reset static configuration variables to their default values */ @@ -952,6 +944,9 @@ class Translatable extends DataExtension implements PermissionProvider { * Translatable also adds a new tab "Translation" which shows existing * translations, as well as a formaction to create new translations based * on a dropdown with available languages. + * + * This method can be called multiple times on the same FieldList + * because it checks which fields have already been added or modified. * * @todo This is specific to SiteTree and CMSMain * @todo Implement a special "translation mode" which triggers display of the @@ -961,82 +956,85 @@ class Translatable extends DataExtension implements PermissionProvider { function updateCMSFields(FieldList $fields) { $this->addTranslatableFields($fields); - if ($this->owner->translatableFieldsAdded) return; - // Show a dropdown to create a new translation. // This action is possible both when showing the "default language" // and a translation. Include the current locale (record might not be saved yet). $alreadyTranslatedLocales = $this->getTranslatedLocales(); $alreadyTranslatedLocales[$this->owner->Locale] = $this->owner->Locale; $alreadyTranslatedLocales = array_combine($alreadyTranslatedLocales, $alreadyTranslatedLocales); - - $fields->addFieldsToTab( - 'Root', - new Tab('Translations', _t('Translatable.TRANSLATIONS', 'Translations'), - new HeaderField('CreateTransHeader', _t('Translatable.CREATE', 'Create new translation'), 2), - $langDropdown = new LanguageDropdownField( - "NewTransLang", - _t('Translatable.NEWLANGUAGE', 'New language'), - $alreadyTranslatedLocales, - 'SiteTree', - 'Locale-English', - $this->owner - ), - $createButton = new InlineFormAction( - 'createtranslation', - _t('Translatable.CREATEBUTTON', 'Create') - ) - ) - ); - $createButton->includeDefaultJS(false); - - if ( count($langDropdown->getSource()) < 1 ) { - $fields->insertAfter( - new LiteralField( + + // Check if fields exist already to avoid adding them twice on repeat invocations + $tab = $fields->findOrMakeTab('Root.Translations', _t('Translatable.TRANSLATIONS', 'Translations')); + if(!$tab->fieldByName('CreateTransHeader')) { + $tab->push(new HeaderField( + 'CreateTransHeader', + _t('Translatable.CREATE', 'Create new translation'), + 2 + )); + } + if(!$tab->fieldByName('NewTransLang') && !$tab->fieldByName('AllTransCreated')) { + $langDropdown = LanguageDropdownField::create( + "NewTransLang", + _t('Translatable.NEWLANGUAGE', 'New language'), + $alreadyTranslatedLocales, + 'SiteTree', + 'Locale-English', + $this->owner + )->addExtraClass('languageDropdown no-change-track'); + $tab->push($langDropdown); + $canAddLocale = (count($langDropdown->getSource()) > 0); + + if($canAddLocale) { + // Only add create button if new languages are available + $tab->push( + $createButton = InlineFormAction::create( + 'createtranslation', + _t('Translatable.CREATEBUTTON', 'Create') + )->addExtraClass('createTranslationButton') + ); + $createButton->includeDefaultJS(false); // not fluent API... + } else { + $tab->removeByName('NewTransLang'); + $tab->push(new LiteralField( 'AllTransCreated', _t('Translatable.ALLCREATED', 'All allowed translations have been created.') - ), - 'CreateTransHeader' - ); - $fields->removeByName('NewTransLang'); - $fields->removeByName('createtranslation'); + )); + } } - if($alreadyTranslatedLocales) { - $fields->addFieldToTab( - 'Root.Translations', - new HeaderField('ExistingTransHeader', _t('Translatable.EXISTING', 'Existing translations'), 3) - ); - $existingTransHTML = ''; - $fields->addFieldToTab( - 'Root.Translations', - new LiteralField('existingtrans',$existingTransHTML) - ); - } - - $langDropdown->addExtraClass('languageDropdown no-change-track'); - $createButton->addExtraClass('createTranslationButton'); - - $this->owner->translatableFieldsAdded = true; - + } } function updateSettingsFields(&$fields) { $this->addTranslatableFields($fields); } + /** + * This method can be called multiple times on the same FieldList + * because it checks which fields have already been added or modified. + */ protected function addTranslatableFields(&$fields) { - // used in LeftAndMain->init() to set language state when reading/writing record $fields->push(new HiddenField("Locale", "Locale", $this->owner->Locale)); @@ -1061,17 +1059,10 @@ class Translatable extends DataExtension implements PermissionProvider { 'NewTransLang', 'createtranslation' ); - - $this->translatableExcludes = ( isset($this->translatableExcludes) && is_array($this->translatableExcludes) ) - ? array_merge($this->translatableExcludes, $excludeFields) - : $excludeFields; - // if a language other than default language is used, we're in "translation mode", // hence have to modify the original fields - $creating = false; $baseClass = $this->owner->class; - $allFields = $fields->toArray(); while( ($p = get_parent_class($baseClass)) != "DataObject") $baseClass = $p; // try to get the record in "default language" @@ -1085,8 +1076,6 @@ class Translatable extends DataExtension implements PermissionProvider { $isTranslationMode = $this->owner->Locale != Translatable::default_locale(); if($originalRecord && $isTranslationMode) { - $originalLangID = Session::get($this->owner->ID . '_originalLangID'); - // Remove parent page dropdown $fields->removeByName("ParentType"); $fields->removeByName("ParentID"); @@ -1099,18 +1088,22 @@ class Translatable extends DataExtension implements PermissionProvider { // iterate through sequential list of all datafields in fieldset // (fields are object references, so we can replace them with the translatable CompositeField) foreach($allDataFields as $dataField) { + // Transformation is a visual helper for CMS authors, so ignore hidden fields if($dataField instanceof HiddenField) continue; - if(in_array($dataField->getName(), $this->translatableExcludes)) continue; + // Some fields are explicitly excluded from transformation + if(in_array($dataField->getName(), $excludeFields)) continue; + // Readonly field which has been added previously + if(preg_match('/_original$/', $dataField->getName())) continue; + // Field already has been transformed + if(isset($allDataFields[$dataField->getName() . '_original'])) continue; if(in_array($dataField->getName(), $translatableFieldNames)) { // if the field is translatable, perform transformation $fields->replaceField($dataField->getName(), $transformation->transformFormField($dataField)); - } else { + } elseif(!$dataField->isReadonly()) { // else field shouldn't be editable in translation-mode, make readonly $fields->replaceField($dataField->getName(), $dataField->performReadonlyTransformation()); } - $this->translatableExcludes[] = $dataField->getName(); - $this->translatableExcludes[] = $dataField->getName() . '_original'; } } elseif($this->owner->isNew()) { @@ -1128,8 +1121,7 @@ class Translatable extends DataExtension implements PermissionProvider { } /** - * Get the names of all translatable fields on this class - * as a numeric array. + * Get the names of all translatable fields on this class as a numeric array. * @todo Integrate with blacklist once branches/translatable is merged back. * * @return array