Issue #1188388 by plach, peximo, YesCT | Gábor Hojtsy, fago, webchick, Bojhan, podarok, cosmicdreams, Berdir, aspilicious, bforchhammer, penyaskito: Added Entity translation UI in core.
2012-11-04 02:38:49 +00:00
< ? php
/**
* @ file
2013-06-25 19:16:20 +00:00
* The content translation administration forms .
Issue #1188388 by plach, peximo, YesCT | Gábor Hojtsy, fago, webchick, Bojhan, podarok, cosmicdreams, Berdir, aspilicious, bforchhammer, penyaskito: Added Entity translation UI in core.
2012-11-04 02:38:49 +00:00
*/
use Drupal\Core\Entity\EntityInterface ;
2013-10-19 08:12:13 +00:00
use Drupal\Core\Field\FieldDefinitionInterface ;
2013-05-25 20:12:45 +00:00
use Drupal\Core\Language\Language ;
2013-10-14 15:40:28 +00:00
use Drupal\field\Field as FieldService ;
Issue #1188388 by plach, peximo, YesCT | Gábor Hojtsy, fago, webchick, Bojhan, podarok, cosmicdreams, Berdir, aspilicious, bforchhammer, penyaskito: Added Entity translation UI in core.
2012-11-04 02:38:49 +00:00
2012-12-29 08:13:54 +00:00
/**
2013-02-19 06:57:04 +00:00
* Returns a form element to configure field synchronization .
2012-12-29 08:13:54 +00:00
*
2013-10-19 08:12:13 +00:00
* @ param \Drupal\Core\Field\FieldDefinitionInterface $field
2013-10-04 07:55:32 +00:00
* A field definition object .
2013-02-19 06:57:04 +00:00
*
* @ return array
* A form element to configure field synchronization .
*/
2013-10-04 07:55:32 +00:00
function content_translation_field_sync_widget ( FieldDefinitionInterface $field ) {
2013-02-19 06:57:04 +00:00
$element = array ();
2013-12-09 23:19:58 +00:00
$column_groups = $field -> getSetting ( 'column_groups' );
2013-10-04 07:55:32 +00:00
if ( ! empty ( $column_groups ) && count ( $column_groups ) > 1 ) {
2013-02-19 06:57:04 +00:00
$options = array ();
$default = array ();
2013-10-04 07:55:32 +00:00
foreach ( $column_groups as $group => $info ) {
2013-02-19 06:57:04 +00:00
$options [ $group ] = $info [ 'label' ];
$default [ $group ] = ! empty ( $info [ 'translatable' ]) ? $group : FALSE ;
}
2013-03-10 06:18:48 +00:00
$settings = array ( 'dependent_selectors' => array ( 'instance[settings][translation_sync]' => array ( 'file' )));
2013-12-09 23:19:58 +00:00
$translation_sync = $field -> getSetting ( 'translation_sync' );
2013-02-19 06:57:04 +00:00
$element = array (
'#type' => 'checkboxes' ,
'#title' => t ( 'Translatable elements' ),
'#options' => $options ,
2013-10-04 07:55:32 +00:00
'#default_value' => ! empty ( $translation_sync ) ? $translation_sync : $default ,
2013-03-10 06:18:48 +00:00
'#attached' => array (
2013-06-05 17:43:43 +00:00
'library' => array (
2013-06-25 19:16:20 +00:00
array ( 'content_translation' , 'drupal.content_translation.admin' ),
2013-06-05 17:43:43 +00:00
),
2013-03-10 06:18:48 +00:00
'js' => array (
2013-06-25 19:16:20 +00:00
array ( 'data' => array ( 'contentTranslationDependentOptions' => $settings ), 'type' => 'setting' ),
2013-03-10 06:18:48 +00:00
),
),
2013-02-19 06:57:04 +00:00
);
}
return $element ;
}
/**
* ( proxied ) Implements hook_form_FORM_ID_alter () .
2012-12-29 08:13:54 +00:00
*/
2013-06-25 19:16:20 +00:00
function _content_translation_form_language_content_settings_form_alter ( array & $form , array & $form_state ) {
2012-12-29 08:13:54 +00:00
// Inject into the content language settings the translation settings if the
// user has the required permission.
2013-06-25 19:16:20 +00:00
if ( ! user_access ( 'administer content translation' )) {
2012-12-29 08:13:54 +00:00
return ;
}
$default = $form [ 'entity_types' ][ '#default_value' ];
foreach ( $default as $entity_type => $enabled ) {
2013-06-25 19:16:20 +00:00
$default [ $entity_type ] = $enabled || content_translation_enabled ( $entity_type ) ? $entity_type : FALSE ;
2012-12-29 08:13:54 +00:00
}
$form [ 'entity_types' ][ '#default_value' ] = $default ;
2013-06-25 19:16:20 +00:00
$form [ '#attached' ][ 'library' ][] = array ( 'content_translation' , 'drupal.content_translation.admin' );
$form [ '#attached' ][ 'js' ][] = array ( 'data' => drupal_get_path ( 'module' , 'content_translation' ) . '/content_translation.admin.js' , 'type' => 'file' );
2012-12-29 08:13:54 +00:00
2013-03-10 06:18:48 +00:00
$dependent_options_settings = array ();
2013-10-14 15:40:28 +00:00
$entity_manager = Drupal :: entityManager ();
2012-12-29 08:13:54 +00:00
foreach ( $form [ '#labels' ] as $entity_type => $label ) {
2014-01-01 10:08:57 +00:00
$entity_info = \Drupal :: entityManager () -> getDefinition ( $entity_type );
2013-01-23 17:46:47 +00:00
foreach ( entity_get_bundles ( $entity_type ) as $bundle => $bundle_info ) {
2012-12-29 08:13:54 +00:00
// Here we do not want the widget to be altered and hold also the "Enable
// translation" checkbox, which would be redundant. Hence we add this key
// to be able to skip alterations.
2013-06-25 19:16:20 +00:00
$form [ 'settings' ][ $entity_type ][ $bundle ][ 'settings' ][ 'language' ][ '#content_translation_skip_alter' ] = TRUE ;
2012-12-29 08:13:54 +00:00
2013-05-06 10:31:46 +00:00
// Only show the checkbox to enable translation if the bundles in the
// entity might have fields and if there are fields to translate.
2014-01-01 10:08:57 +00:00
if ( $entity_info -> isFieldable ()) {
2013-10-14 15:40:28 +00:00
$fields = $entity_manager -> getFieldDefinitions ( $entity_type , $bundle );
if ( $fields ) {
2013-05-06 10:31:46 +00:00
$form [ 'settings' ][ $entity_type ][ $bundle ][ 'translatable' ] = array (
'#type' => 'checkbox' ,
2013-06-25 19:16:20 +00:00
'#default_value' => content_translation_enabled ( $entity_type , $bundle ),
2013-05-06 10:31:46 +00:00
);
2013-10-14 15:40:28 +00:00
$field_settings = content_translation_get_config ( $entity_type , $bundle , 'fields' );
foreach ( $fields as $field_name => $definition ) {
$translatable = ! empty ( $field_settings [ $field_name ]);
// We special case Field API fields as they always natively support
// translation.
// @todo Remove this special casing as soon as configurable and
// base field definitions are "unified".
2013-12-09 23:19:58 +00:00
if ( $definition -> isConfigurable () && ( $field = FieldService :: fieldInfo () -> getField ( $entity_type , $field_name ))) {
2013-10-14 15:40:28 +00:00
$instance = FieldService :: fieldInfo () -> getInstance ( $entity_type , $bundle , $field_name );
$form [ 'settings' ][ $entity_type ][ $bundle ][ 'fields' ][ $field_name ] = array (
2013-12-09 23:19:58 +00:00
'#label' => $instance -> getLabel (),
2013-10-14 15:40:28 +00:00
'#type' => 'checkbox' ,
'#default_value' => $translatable ,
);
$column_element = content_translation_field_sync_widget ( $instance );
if ( $column_element ) {
$form [ 'settings' ][ $entity_type ][ $bundle ][ 'columns' ][ $field_name ] = $column_element ;
// @todo This should not concern only files.
if ( isset ( $column_element [ '#options' ][ 'file' ])) {
$dependent_options_settings [ " settings[ { $entity_type } ][ { $bundle } ][columns][ { $field_name } ] " ] = array ( 'file' );
}
2013-05-06 10:31:46 +00:00
}
}
2013-10-14 15:40:28 +00:00
// Instead we need to rely on field definitions to determine whether
// fields support translation. Whether they are actually enabled is
// determined through our settings. As a consequence only fields
// that support translation can be enabled or disabled.
2013-12-09 23:19:58 +00:00
elseif ( isset ( $field_settings [ $field_name ]) || $definition -> isTranslatable ()) {
2013-10-14 15:40:28 +00:00
$form [ 'settings' ][ $entity_type ][ $bundle ][ 'fields' ][ $field_name ] = array (
2013-12-06 10:56:29 +00:00
'#label' => $definition -> getLabel (),
2013-10-14 15:40:28 +00:00
'#type' => 'checkbox' ,
'#default_value' => $translatable ,
);
}
2013-03-10 06:18:48 +00:00
}
2013-02-19 06:57:04 +00:00
}
2012-12-29 08:13:54 +00:00
}
}
}
2013-03-10 06:18:48 +00:00
$settings = array ( 'dependent_selectors' => $dependent_options_settings );
2013-06-25 19:16:20 +00:00
$form [ '#attached' ][ 'js' ][] = array ( 'data' => array ( 'contentTranslationDependentOptions' => $settings ), 'type' => 'setting' );
$form [ '#validate' ][] = 'content_translation_form_language_content_settings_validate' ;
$form [ '#submit' ][] = 'content_translation_form_language_content_settings_submit' ;
2012-12-29 08:13:54 +00:00
}
2013-02-19 06:57:04 +00:00
/**
* ( proxied ) Implements hook_preprocess_HOOK ();
*/
2013-06-25 19:16:20 +00:00
function _content_translation_preprocess_language_content_settings_table ( & $variables ) {
2013-02-19 06:57:04 +00:00
// Alter the 'build' variable injecting the translation settings if the user
// has the required permission.
2013-06-25 19:16:20 +00:00
if ( ! user_access ( 'administer content translation' )) {
2013-02-19 06:57:04 +00:00
return ;
}
$element = $variables [ 'element' ];
$build = & $variables [ 'build' ];
array_unshift ( $build [ '#header' ], array ( 'data' => t ( 'Translatable' ), 'class' => array ( 'translatable' )));
$rows = array ();
foreach ( element_children ( $element ) as $bundle ) {
$field_names = ! empty ( $element [ $bundle ][ 'fields' ]) ? element_children ( $element [ $bundle ][ 'fields' ]) : array ();
2013-05-06 10:31:46 +00:00
if ( ! empty ( $element [ $bundle ][ 'translatable' ])) {
$checkbox_id = $element [ $bundle ][ 'translatable' ][ '#id' ];
}
2013-02-19 06:57:04 +00:00
$rows [ $bundle ] = $build [ '#rows' ][ $bundle ];
2013-05-06 10:31:46 +00:00
if ( ! empty ( $element [ $bundle ][ 'translatable' ])) {
$translatable = array (
'data' => $element [ $bundle ][ 'translatable' ],
'class' => array ( 'translatable' ),
);
array_unshift ( $rows [ $bundle ][ 'data' ], $translatable );
2013-02-19 06:57:04 +00:00
2013-05-06 10:31:46 +00:00
$rows [ $bundle ][ 'data' ][ 1 ][ 'data' ][ '#prefix' ] = '<label for="' . $checkbox_id . '">' ;
}
else {
$translatable = array (
'class' => array ( 'untranslatable' ),
);
array_unshift ( $rows [ $bundle ][ 'data' ], $translatable );
}
2013-02-19 06:57:04 +00:00
foreach ( $field_names as $field_name ) {
$field_element = & $element [ $bundle ][ 'fields' ][ $field_name ];
$rows [] = array (
'data' => array (
array (
'data' => drupal_render ( $field_element ),
'class' => array ( 'translatable' ),
),
array (
'data' => array (
'#prefix' => '<label for="' . $field_element [ '#id' ] . '">' ,
'#suffix' => '</label>' ,
'bundle' => array (
2013-06-17 19:58:27 +00:00
'#prefix' => '<span class="visually-hidden">' ,
2013-02-19 06:57:04 +00:00
'#suffix' => '</span> ' ,
'#markup' => check_plain ( $element [ $bundle ][ 'settings' ][ '#label' ]),
),
'field' => array (
'#markup' => check_plain ( $field_element [ '#label' ]),
),
),
'class' => array ( 'field' ),
),
array (
'data' => '' ,
'class' => array ( 'operations' ),
),
),
'class' => array ( 'field-settings' ),
);
if ( ! empty ( $element [ $bundle ][ 'columns' ][ $field_name ])) {
$column_element = & $element [ $bundle ][ 'columns' ][ $field_name ];
foreach ( element_children ( $column_element ) as $key ) {
$column_label = $column_element [ $key ][ '#title' ];
unset ( $column_element [ $key ][ '#title' ]);
$rows [] = array (
'data' => array (
array (
'data' => drupal_render ( $column_element [ $key ]),
'class' => array ( 'translatable' ),
),
array (
'data' => array (
'#prefix' => '<label for="' . $column_element [ $key ][ '#id' ] . '">' ,
'#suffix' => '</label>' ,
'bundle' => array (
2013-06-17 19:58:27 +00:00
'#prefix' => '<span class="visually-hidden">' ,
2013-02-19 06:57:04 +00:00
'#suffix' => '</span> ' ,
'#markup' => check_plain ( $element [ $bundle ][ 'settings' ][ '#label' ]),
),
'field' => array (
2013-06-17 19:58:27 +00:00
'#prefix' => '<span class="visually-hidden">' ,
2013-02-19 06:57:04 +00:00
'#suffix' => '</span> ' ,
'#markup' => check_plain ( $field_element [ '#label' ]),
),
'columns' => array (
'#markup' => check_plain ( $column_label ),
),
),
'class' => array ( 'column' ),
),
array (
'data' => '' ,
'class' => array ( 'operations' ),
),
),
'class' => array ( 'column-settings' ),
);
}
}
}
}
$build [ '#rows' ] = $rows ;
}
2012-12-29 08:13:54 +00:00
/**
2013-06-25 19:16:20 +00:00
* Form validation handler for content_translation_admin_settings_form () .
2012-12-29 08:13:54 +00:00
*
2013-06-25 19:16:20 +00:00
* @ see content_translation_admin_settings_form_submit ()
2012-12-29 08:13:54 +00:00
*/
2013-06-25 19:16:20 +00:00
function content_translation_form_language_content_settings_validate ( array $form , array & $form_state ) {
2012-12-29 08:13:54 +00:00
$settings = & $form_state [ 'values' ][ 'settings' ];
foreach ( $settings as $entity_type => $entity_settings ) {
foreach ( $entity_settings as $bundle => $bundle_settings ) {
if ( ! empty ( $bundle_settings [ 'translatable' ])) {
$name = " settings][ $entity_type ][ $bundle ][translatable " ;
$translatable_fields = isset ( $settings [ $entity_type ][ $bundle ][ 'fields' ]) ? array_filter ( $settings [ $entity_type ][ $bundle ][ 'fields' ]) : FALSE ;
if ( empty ( $translatable_fields )) {
$t_args = array ( '%bundle' => $form [ 'settings' ][ $entity_type ][ $bundle ][ 'settings' ][ '#label' ]);
2013-11-23 20:57:04 +00:00
form_set_error ( $name , $form_state , t ( 'At least one field needs to be translatable to enable %bundle for translation.' , $t_args ));
2012-12-29 08:13:54 +00:00
}
$values = $bundle_settings [ 'settings' ][ 'language' ];
Issue #1862202 by plach, Berdir, katbailey, ParisLiakos, alexpott, chx, sun, larowlan, Gábor Hojtsy, cosmicdreams, vijaycs85, YesCT, penyaskito, andypost, Albert Volkman, joelpitett: Objectify the language system.
2014-01-15 16:27:37 +00:00
if ( empty ( $values [ 'language_show' ]) && \Drupal :: languageManager () -> isLanguageLocked ( $values [ 'langcode' ])) {
2013-05-25 20:12:45 +00:00
foreach ( language_list ( Language :: STATE_LOCKED ) as $language ) {
2012-12-29 08:13:54 +00:00
$locked_languages [] = $language -> name ;
}
2013-11-23 20:57:04 +00:00
form_set_error ( $name , $form_state , t ( 'Translation is not supported if language is always one of: @locked_languages' , array ( '@locked_languages' => implode ( ', ' , $locked_languages ))));
2012-12-29 08:13:54 +00:00
}
}
}
}
}
/**
2013-06-25 19:16:20 +00:00
* Form submission handler for content_translation_admin_settings_form () .
2012-12-29 08:13:54 +00:00
*
2013-06-25 19:16:20 +00:00
* @ see content_translation_admin_settings_form_validate ()
2012-12-29 08:13:54 +00:00
*/
2013-06-25 19:16:20 +00:00
function content_translation_form_language_content_settings_submit ( array $form , array & $form_state ) {
2012-12-29 08:13:54 +00:00
$entity_types = $form_state [ 'values' ][ 'entity_types' ];
$settings = & $form_state [ 'values' ][ 'settings' ];
// If an entity type is not translatable all its bundles and fields must be
// marked as non-translatable. Similarly, if a bundle is made non-translatable
// all of its fields will be not translatable.
foreach ( $settings as $entity_type => & $entity_settings ) {
2013-12-22 20:20:45 +00:00
foreach ( $entity_settings as & $bundle_settings ) {
2013-05-06 10:31:46 +00:00
if ( ! empty ( $bundle_settings [ 'translatable' ])) {
$bundle_settings [ 'translatable' ] = $bundle_settings [ 'translatable' ] && $entity_types [ $entity_type ];
}
2012-12-29 08:13:54 +00:00
if ( ! empty ( $bundle_settings [ 'fields' ])) {
foreach ( $bundle_settings [ 'fields' ] as $field_name => $translatable ) {
$bundle_settings [ 'fields' ][ $field_name ] = $translatable && $bundle_settings [ 'translatable' ];
2013-02-19 06:57:04 +00:00
// If we have column settings and no column is translatable, no point
// in making the field translatable.
if ( isset ( $bundle_settings [ 'columns' ][ $field_name ]) && ! array_filter ( $bundle_settings [ 'columns' ][ $field_name ])) {
$bundle_settings [ 'fields' ][ $field_name ] = FALSE ;
}
2012-12-29 08:13:54 +00:00
}
}
}
}
2013-06-25 19:16:20 +00:00
_content_translation_update_field_translatability ( $settings );
2012-12-29 08:13:54 +00:00
drupal_set_message ( t ( 'Settings successfully updated.' ));
}
/**
2013-06-25 19:16:20 +00:00
* Stores content translation settings .
2012-12-29 08:13:54 +00:00
*
* @ param array $settings
* An associative array of settings keyed by entity type and bundle . At bundle
* level the following keys are available :
* - translatable : The bundle translatability status , which is a bool .
* - settings : An array of language configuration settings as defined by
* language_save_default_configuration () .
* - fields : An associative array with field names as keys and a boolean as
* value , indicating field translatability .
*/
2013-06-25 19:16:20 +00:00
function _content_translation_update_field_translatability ( $settings ) {
2013-12-04 16:37:16 +00:00
// Update translatability for configurable fields.
// @todo Remove this once configurable fields rely on entity field info to
// track translatability. See https://drupal.org/node/2018685.
2012-12-29 08:13:54 +00:00
foreach ( $settings as $entity_type => $entity_settings ) {
2013-12-04 16:37:16 +00:00
$fields = array ();
2013-12-22 20:20:45 +00:00
foreach ( $entity_settings as $bundle_settings ) {
2012-12-29 08:13:54 +00:00
// Collapse field settings since here we have per instance settings, but
// translatability has per-field scope. We assume that all the field
// instances have the same value.
if ( ! empty ( $bundle_settings [ 'fields' ])) {
foreach ( $bundle_settings [ 'fields' ] as $field_name => $translatable ) {
2013-12-04 16:37:16 +00:00
// If translatability changes for at least one field instance we need
// to switch field translatability.
2013-11-28 08:25:13 +00:00
$field = FieldService :: fieldInfo () -> getField ( $entity_type , $field_name );
2013-12-09 23:19:58 +00:00
if ( $field && $field -> isTranslatable () !== $translatable ) {
2013-12-04 16:37:16 +00:00
$fields [ $field_name ] = $translatable ;
2013-10-14 15:40:28 +00:00
}
2012-12-29 08:13:54 +00:00
}
}
}
2013-12-04 16:37:16 +00:00
// Store updated fields.
foreach ( $fields as $field_name => $translatable ) {
$field = FieldService :: fieldInfo () -> getField ( $entity_type , $field_name );
$field -> translatable = $translatable ;
$field -> save ();
}
2012-12-29 08:13:54 +00:00
}
2013-11-28 08:25:13 +00:00
content_translation_save_settings ( $settings );
Issue #1188388 by plach, peximo, YesCT | Gábor Hojtsy, fago, webchick, Bojhan, podarok, cosmicdreams, Berdir, aspilicious, bforchhammer, penyaskito: Added Entity translation UI in core.
2012-11-04 02:38:49 +00:00
}