diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php index 9c3af8e..40afc94 100644 --- a/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php +++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentLanguageTest.php @@ -47,7 +47,7 @@ class CommentLanguageTest extends WebTestBase { $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language')); // Set "Article" content type to use multilingual support. - $edit = array('node_type_language_hidden' => FALSE); + $edit = array('language_configuration[language_hidden]' => FALSE); $this->drupalPost('admin/structure/types/manage/article', $edit, t('Save content type')); // Enable content language negotiation UI. diff --git a/core/modules/field/modules/text/lib/Drupal/text/Tests/TextTranslationTest.php b/core/modules/field/modules/text/lib/Drupal/text/Tests/TextTranslationTest.php index 77e6937..0ac151f 100644 --- a/core/modules/field/modules/text/lib/Drupal/text/Tests/TextTranslationTest.php +++ b/core/modules/field/modules/text/lib/Drupal/text/Tests/TextTranslationTest.php @@ -51,7 +51,7 @@ class TextTranslationTest extends WebTestBase { $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language')); // Set "Article" content type to use multilingual support with translation. - $edit = array('node_type_language_hidden' => FALSE, 'node_type_language_translation_enabled' => TRUE); + $edit = array('language_configuration[language_hidden]' => FALSE, 'node_type_language_translation_enabled' => TRUE); $this->drupalPost('admin/structure/types/manage/article', $edit, t('Save content type')); $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Article')), 'Article content type has been updated.'); } diff --git a/core/modules/language/language.module b/core/modules/language/language.module index 5b62382..94a4c2f 100644 --- a/core/modules/language/language.module +++ b/core/modules/language/language.module @@ -216,6 +216,8 @@ function language_process_language_select($element) { if (!isset($element['#options'])) { $element['#options'] = array(); foreach (language_list($element['#languages']) as $langcode => $language) { + // @todo: http://drupal.org/node/1739928#comment-6471438 + // Is this flipped? If it's locked, put it in t() so it can be translated? $element['#options'][$langcode] = $language->locked ? t('- @name -', array('@name' => $language->name)) : $language->name; } } @@ -223,6 +225,224 @@ function language_process_language_select($element) { } /** + * Implements hook_element_info(). + */ +function language_element_info() { + $types['language_configuration'] = array( + '#input' => TRUE, + '#tree' => TRUE, + '#process' => array('language_configuration_element_process'), + ); + return $types; +} + +/** + * Returns the default options for the language configuration form element. + * + * @return array + * An array containing the default options. + */ +function language_configuration_element_default_options() { + $language_options = array(); + + $languages = language_list(LANGUAGE_ALL); + foreach ($languages as $langcode => $language) { + $language_options[$langcode] = $language->locked ? t('- @name -', array('@name' => $language->name)) : $language->name; + } + + $language_options += array( + 'site_default' => t("Site's default language (!language)", array('!language' => language_default()->name)), + 'current_interface' => t('Current interface language'), + 'authors_default' => t("Author's preferred language"), + ); + return $language_options; +} + +/** + * Process handler for the language_configuration form element. + */ +function language_configuration_element_process($element, &$form_state, &$form) { + $options = isset($element['#options']) ? $element['#options'] : array(); + // Avoid validation failure since we are moving the '#options' key in the + // nested 'language' select element. + unset($element['#options']); + $element['langcode'] = array( + '#type' => 'select', + '#title' => t('Default language'), + '#options' => $options + language_configuration_element_default_options(), + '#description' => t('Explanation of the language options is found on the languages list page.', array('@languages_list_page' => url('admin/config/regional/language'))), + '#default_value' => isset($element['#default_value']['langcode']) ? $element['#default_value']['langcode'] : NULL, + ); + + $element['language_hidden'] = array( + '#type' => 'checkbox', + '#title' => t('Hide language selection'), + '#default_value' => isset($element['#default_value']['language_hidden']) ? $element['#default_value']['language_hidden'] : NULL, + '#description' => t('Language selector appears on create and edit pages.'), + ); + + // Add the entity type and bundle information to the form if they are set. + // They will be used, in the submit handler, to generate the names of the + // variables that will store the settings and are a way to uniquely identify + // the entity. + if (!isset($form_state['language'])) { + $form_state['language'] = array(); + } + $form_state['language'] += array( + $element['#name'] => array( + 'entity_type' => $element['#entity_information']['entity_type'], + 'bundle' => $element['#entity_information']['bundle'], + ), + ); + + return $element; +} + +/** + * Submit handler for the forms that have a language_configuration element. + */ +function language_configuration_element_submit(&$form, &$form_state) { + // Iterate through all the language_configuration elements and save their + // values. + if (isset($form_state['language'])) { + foreach ($form_state['language'] as $element_name => $values) { + language_save_default_configuration($values['entity_type'], $values['bundle'], $form_state['values'][$element_name]); + } + } +} + +/** + * Saves a language configuration that is attached to an entity type and bundle. + * + * @param string $entity_type + * A string representing the entity type. + * @param string $bundle + * A string representing the bundle. + * @param array $values + * An array holding the values to be saved having the following keys: + * - langcode: the language code. + * - language_hidden: if the language element should be hidden or not. + */ +function language_save_default_configuration($entity_type, $bundle, $values = array()) { + config('language.settings')->set(language_get_default_configuration_settings_path($entity_type, $bundle), array('langcode' => $values['langcode'], 'language_hidden' => $values['language_hidden']))->save(); +} + +/** + * Returns the language configuration stored for an entity type and bundle. + * + * @param string $entity_type + * A string representing the entity type. + * @param string $bundle + * A string representing the bundle. + * + * @return array + * An array with the following keys: + * - langcode: the language code. + * - language_hidden: if the language element is hidden or not. + */ +function language_get_default_configuration($entity_type, $bundle) { + // @todo: http://drupal.org/node/1783346 for unresolved CMI issue. + $configuration = config('language.settings')->get(language_get_default_configuration_settings_path($entity_type, $bundle)); + if (is_null($configuration)) { + $configuration = array(); + } + $configuration += array('langcode' => 'site_default', 'language_hidden' => TRUE); + return $configuration; +} + +/** + * Clears the default language configuration for an entity type and bundle. + * + * @param string $entity_type + * A string representing the entity type. + * @param string $bundle + * A string representing the bundle. + */ +function language_clear_default_configuration($entity_type, $bundle) { + config('language.settings')->clear(language_get_default_configuration_settings_path($entity_type, $bundle))->save(); +} + +/** + * Returns the root name of the variables used to store the configuration. + * + * Based on the entity type and bundle, the variables used to store the + * configuration will have a common root name. + * + * @param string $entity_type + * A string representing the entity type. + * @param string $bundle + * A string representing the bundle. + * + * @return string + * The root name of the variables. + */ +function language_get_default_configuration_settings_path($entity_type, $bundle) { + // @todo: http://drupal.org/node/1739928#comment-6471438 + // Since these values are more or less coming in directly from + // $form_state['values'], should there be some sanitization here to ensure + // people aren't putting nonsense like "../../../../" in there? + return $entity_type . '.' . $bundle . '.language.default_configuration'; +} + +/** + * Implements hook_node_type_update(). + */ +function language_node_type_update($info) { + if (!empty($info->old_type) && $info->old_type != $info->type) { + language_save_default_configuration('node', $info->type, language_get_default_configuration('node', $info->old_type)); + language_clear_default_configuration('node', $info->old_type); + } +} + +/** + * Returns the default language code assigned to an entity type and a bundle. + * + * @param string $entity_type + * The entity type. + * @param string $bundle + * The bundle name. + * + * @return string + * The language code. + */ +function language_get_default_langcode($entity_type, $bundle) { + $configuration = language_get_default_configuration($entity_type, $bundle); + + if (!isset($configuration['langcode'])) { + $configuration['langcode'] = 'site_default'; + } + + $default_value = NULL; + $language_interface = language(LANGUAGE_TYPE_INTERFACE); + switch ($configuration['langcode']) { + case 'site_default': + $default_value = language_default()->langcode; + break; + + case 'current_interface': + $default_value = $language_interface->langcode; + break; + + case 'authors_default': + global $user; + if (!empty($user->preferred_langcode)) { + $default_value = $user->preferred_langcode; + } + else { + $default_value = $language_interface->langcode; + } + break; + } + if ($default_value) { + return $default_value; + } + + // If we still do not have a default value, just return the value stored in + // the configuration; it has to be an actual language code. + return $configuration['langcode']; +} + +/** * API function to add or update a language. * * @param $language @@ -282,6 +502,7 @@ function language_update_count() { * * @param $langcode * Language code of the language to be deleted. + * * @return * TRUE if language is successfully deleted. Otherwise FALSE. */ diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationElementTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationElementTest.php new file mode 100644 index 0000000..6f8d9c8 --- /dev/null +++ b/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationElementTest.php @@ -0,0 +1,140 @@ + 'Language configuration form element tests', + 'description' => 'Tests the features of the language configuration element field.', + 'group' => 'Language', + ); + } + + /** + * Tests the language settings have been saved. + */ + public function testLanguageConfigurationElement() { + $this->drupalGet('language-tests/language_configuration_element'); + $edit['lang_configuration[langcode]'] = 'current_interface'; + $edit['lang_configuration[language_hidden]'] = TRUE; + $this->drupalPost(NULL, $edit, 'Save'); + $lang_conf = language_get_default_configuration('some_custom_type', 'some_bundle'); + + // Check that the settings have been saved. + $this->assertEqual($lang_conf['langcode'], 'current_interface'); + $this->assertTrue($lang_conf['language_hidden']); + $this->drupalGet('language-tests/language_configuration_element'); + $this->assertOptionSelected('edit-lang-configuration-langcode', 'current_interface'); + $this->assertFieldChecked('edit-lang-configuration-language-hidden'); + + // Reload the page and save again. + $this->drupalGet('language-tests/language_configuration_element'); + $edit['lang_configuration[langcode]'] = 'authors_default'; + $edit['lang_configuration[language_hidden]'] = FALSE; + $this->drupalPost(NULL, $edit, 'Save'); + $lang_conf = language_get_default_configuration('some_custom_type', 'some_bundle'); + + // Check that the settings have been saved. + $this->assertEqual($lang_conf['langcode'], 'authors_default'); + $this->assertFalse($lang_conf['language_hidden']); + $this->drupalGet('language-tests/language_configuration_element'); + $this->assertOptionSelected('edit-lang-configuration-langcode', 'authors_default'); + $this->assertNoFieldChecked('edit-lang-configuration-language-hidden'); + } + + /** + * Tests that the language_get_default_langcode() returns the correct values. + */ + public function testDefaultLangcode() { + // Add some custom languages. + foreach (array('aa', 'bb', 'cc') as $language_code) { + $language = new Language(array( + 'langcode' => $language_code, + 'name' => $this->randomName(), + )); + language_save($language); + } + + // Fixed language. + language_save_default_configuration('custom_type', 'custom_bundle', array('langcode' => 'bb', 'language_hidden' => FALSE)); + $langcode = language_get_default_langcode('custom_type', 'custom_bundle'); + $this->assertEqual($langcode, 'bb'); + + // Current interface. + language_save_default_configuration('custom_type', 'custom_bundle', array('langcode' => 'current_interface', 'language_hidden' => FALSE)); + $langcode = language_get_default_langcode('custom_type', 'custom_bundle'); + $language_interface = language(LANGUAGE_TYPE_INTERFACE); + $this->assertEqual($langcode, $language_interface->langcode); + + // Site's default. + $old_default = language_default(); + $old_default->default = FALSE; + language_save($old_default); + $new_default = language_load('cc'); + $new_default->default = TRUE; + language_save($new_default); + language_save_default_configuration('custom_type', 'custom_bundle', array('langcode' => 'site_default', 'language_hidden' => FALSE)); + $langcode = language_get_default_langcode('custom_type', 'custom_bundle'); + $this->assertEqual($langcode, 'cc'); + + // Check the default value of a language field when authors preferred option + // is selected. + // Create first an user and assign a preferred langcode to him. + $some_user = $this->drupalCreateUser(); + $some_user->preferred_langcode = 'bb'; + $some_user->save(); + $this->drupalLogin($some_user); + language_save_default_configuration('custom_type', 'some_bundle', array('langcode' => 'authors_default', 'language_hidden' => FALSE)); + $this->drupalGet('language-tests/language_configuration_element_test'); + $this->assertOptionSelected('edit-langcode', 'bb'); + } + + /** + * Tests that the configuration is updated when the node type is changed. + */ + public function testNodeTypeUpdate() { + // Create the article content type first if the profile used is not the + // standard one. + if ($this->profile != 'standard') { + $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article')); + } + $admin_user = $this->drupalCreateUser(array('administer content types')); + $this->drupalLogin($admin_user); + $edit = array( + 'language_configuration[langcode]' => 'current_interface', + 'language_configuration[language_hidden]' => FALSE, + ); + $this->drupalPost('admin/structure/types/manage/article', $edit, t('Save content type')); + // Check the language default configuration for the articles. + $configuration = language_get_default_configuration('node', 'article'); + $this->assertEqual($configuration, array('langcode' => 'current_interface', 'language_hidden' => 0), 'The default language configuration has been saved on the Article content type.'); + // Rename the article content type. + $edit = array( + 'type' => 'article_2' + ); + $this->drupalPost('admin/structure/types/manage/article', $edit, t('Save content type')); + // Check that we still have the settings for the new node type. + $configuration = language_get_default_configuration('node', 'article_2'); + $this->assertEqual($configuration, array('langcode' => 'current_interface', 'language_hidden' => 0), 'The default language configuration has been kept on the new Article content type.'); + } +} diff --git a/core/modules/language/tests/language_elements_test/language_elements_test.info b/core/modules/language/tests/language_elements_test/language_elements_test.info new file mode 100644 index 0000000..c88befb --- /dev/null +++ b/core/modules/language/tests/language_elements_test/language_elements_test.info @@ -0,0 +1,6 @@ +name = "Language form elements test" +description = "Support module for the language form elements tests." +core = 8.x +package = Testing +version = VERSION +hidden = TRUE diff --git a/core/modules/language/tests/language_elements_test/language_elements_test.module b/core/modules/language/tests/language_elements_test/language_elements_test.module new file mode 100644 index 0000000..b44cc45 --- /dev/null +++ b/core/modules/language/tests/language_elements_test/language_elements_test.module @@ -0,0 +1,55 @@ + 'Language configuration form element', + 'type' => MENU_CALLBACK, + 'access callback' => TRUE, + 'page callback' => 'drupal_get_form', + 'page arguments' => array('language_elements_configuration_element'), + ); + $items['language-tests/language_configuration_element_test'] = array( + 'title' => 'Language configuration form element', + 'type' => MENU_CALLBACK, + 'access callback' => TRUE, + 'page callback' => 'drupal_get_form', + 'page arguments' => array('language_elements_configuration_element_test'), + ); + return $items; +} + +function language_elements_configuration_element() { + $conf = language_get_default_configuration('some_custom_type', 'some_bundle'); + + $form['lang_configuration'] = array( + '#type' => 'language_configuration', + '#entity_information' => array( + 'entity_type' => 'some_custom_type', + 'bundle' => 'some_bundle', + ), + '#default_value' => $conf, + ); + + $form['submit'] = array( + '#type' => 'submit', + '#value' => 'Save', + ); + $form['#submit'][] = 'language_configuration_element_submit'; + return $form; +} + +function language_elements_configuration_element_test() { + $form['langcode'] = array( + '#type' => 'language_select', + '#default_value' => language_get_default_langcode('custom_type', 'some_bundle'), + ); + return $form; +} diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php index a41d68b..d30526a 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php @@ -88,7 +88,7 @@ class LocaleContentTest extends WebTestBase { $this->drupalGet('admin/structure/types/manage/page'); $this->assertText(t('Language settings'), t('Multilingual support fieldset present on content type configuration form.')); $edit = array( - 'node_type_language_hidden' => FALSE, + 'language_configuration[language_hidden]' => FALSE, ); $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type')); $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.')); @@ -156,7 +156,7 @@ class LocaleContentTest extends WebTestBase { // Set "Article" content type to use multilingual support. $this->drupalGet('admin/structure/types/manage/article'); $edit = array( - 'node_type_language_hidden' => FALSE, + 'language_configuration[language_hidden]' => FALSE, ); $this->drupalPost('admin/structure/types/manage/article', $edit, t('Save content type')); $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Article')), t('Article content type has been updated.')); diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php index 7591f67..78a38a0 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php @@ -63,7 +63,7 @@ class LocaleUninstallTest extends WebTestBase { $this->assertEqual(language(LANGUAGE_TYPE_INTERFACE)->langcode, $this->langcode, t('Current language: %lang', array('%lang' => language(LANGUAGE_TYPE_INTERFACE)->langcode))); // Enable multilingual workflow option for articles. - variable_set('node_type_language_hidden_article',FALSE); + language_save_default_configuration('node', 'article', array('langcode' => 'site_default', 'language_hidden' => FALSE)); // Change JavaScript translations directory. variable_set('locale_js_directory', 'js_translations'); // Build the JavaScript translation file for French. diff --git a/core/modules/node/content_types.inc b/core/modules/node/content_types.inc index 355a022..c107020 100644 --- a/core/modules/node/content_types.inc +++ b/core/modules/node/content_types.inc @@ -185,19 +185,6 @@ function node_type_form($form, &$form_state, $type = NULL) { '#description' => t('Users with the Administer content permission will be able to override these options.'), ); if (module_exists('language')) { - $lang_options = array(); - - $languages = language_list(LANGUAGE_ALL); - foreach ($languages as $langcode => $language) { - $lang_options[$langcode] = $language->locked ? t('- @name -', array('@name' => $language->name)) : $language->name; - } - - $lang_options += array( - 'site_default' => t("Site's default language"), - 'current_interface' => t('Current interface language'), - 'authors_default' => t("Author's preferred language"), - ); - $form['language'] = array( '#type' => 'fieldset', '#title' => t('Language settings'), @@ -205,18 +192,20 @@ function node_type_form($form, &$form_state, $type = NULL) { '#collapsed' => TRUE, '#group' => 'additional_settings', ); - $form['language']['node_type_language_default'] = array( - '#type' => 'select', - '#title' => t('Default language'), - '#options' => $lang_options, - '#default_value' => variable_get('node_type_language_default_' . $type->type, 'site_default'), - '#description' => t('Explanation of the language options is found on the languages list page.', array('@languages_list_page' => url('admin/config/regional/language'))), - ); - $form['language']['node_type_language_hidden'] = array( - '#type' => 'checkbox', - '#title' => t('Hide language selector'), - '#default_value' => variable_get('node_type_language_hidden_' . $type->type, TRUE), + + // @todo: http://drupal.org/node/1739928#comment-6471438 + // In taxonomy module, this was wrapped in an if (module_exists('language')) + // check. Why is it not here? + $language_configuration = language_get_default_configuration('node', $type->type); + $form['language']['language_configuration'] = array( + '#type' => 'language_configuration', + '#entity_information' => array( + 'entity_type' => 'node', + 'bundle' => $type->type, + ), + '#default_value' => $language_configuration, ); + $form['#submit'][] = 'language_configuration_element_submit'; } $form['display'] = array( '#type' => 'fieldset', @@ -272,6 +261,7 @@ function node_type_form($form, &$form_state, $type = NULL) { ); } } + $form['#submit'][] = 'node_type_form_submit'; return $form; } diff --git a/core/modules/node/content_types.js b/core/modules/node/content_types.js index 87fc460..d2a63b6 100644 --- a/core/modules/node/content_types.js +++ b/core/modules/node/content_types.js @@ -24,7 +24,7 @@ Drupal.behaviors.contentTypes = { $('fieldset#edit-language', context).drupalSetSummary(function(context) { var vals = []; - vals.push($(".form-item-node-type-language-default select option:selected", context).text()); + vals.push($(".form-item-language-configuration-langcode select option:selected", context).text()) $('input:checked', context).next('label').each(function() { vals.push(Drupal.checkPlain($(this).text())); diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php index b9bf7eb..09a8ca8 100644 --- a/core/modules/node/lib/Drupal/node/NodeFormController.php +++ b/core/modules/node/lib/Drupal/node/NodeFormController.php @@ -98,12 +98,13 @@ class NodeFormController extends EntityFormController { $form['title']['#weight'] = -5; } + $language_configuration = module_invoke('language', 'get_default_configuration', 'node', $node->type); $form['langcode'] = array( '#title' => t('Language'), '#type' => 'language_select', '#default_value' => $node->langcode, '#languages' => LANGUAGE_ALL, - '#access' => !variable_get('node_type_language_hidden_' . $node->type, TRUE), + '#access' => isset($language_configuration['language_hidden']) && !$language_configuration['language_hidden'], ); $form['additional_settings'] = array( diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php b/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php index b96dae9..29210a5 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeFieldMultilingualTestCase.php @@ -53,7 +53,7 @@ class NodeFieldMultilingualTestCase extends WebTestBase { // Set "Basic page" content type to use multilingual support. $edit = array( - 'node_type_language_hidden' => FALSE, + 'language_configuration[language_hidden]' => FALSE, ); $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type')); $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.')); @@ -69,7 +69,7 @@ class NodeFieldMultilingualTestCase extends WebTestBase { */ function testMultilingualNodeForm() { // Create "Basic page" content. - $langcode = node_type_get_default_langcode('page'); + $langcode = language_get_default_langcode('node', 'page'); $title_key = "title"; $title_value = $this->randomName(8); $body_key = "body[$langcode][0][value]"; @@ -117,7 +117,7 @@ class NodeFieldMultilingualTestCase extends WebTestBase { */ function testMultilingualDisplaySettings() { // Create "Basic page" content. - $langcode = node_type_get_default_langcode('page'); + $langcode = language_get_default_langcode('node', 'page'); $title_key = "title"; $title_value = $this->randomName(8); $body_key = "body[$langcode][0][value]"; diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTypeInitialLanguageTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTypeInitialLanguageTest.php index e191eca..c2407c2 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeTypeInitialLanguageTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeTypeInitialLanguageTest.php @@ -42,8 +42,8 @@ class NodeTypeInitialLanguageTest extends NodeTestBase { */ function testNodeTypeInitialLanguageDefaults() { $this->drupalGet('admin/structure/types/manage/article'); - $this->assertOptionSelected('edit-node-type-language-default', 'site_default', 'The default inital language is the site default.'); - $this->assertFieldChecked('edit-node-type-language-hidden', 'Language selector is hidden by default.'); + $this->assertOptionSelected('edit-language-configuration-langcode', 'site_default', 'The default inital language is the site default.'); + $this->assertFieldChecked('edit-language-configuration-language-hidden', 'Language selector is hidden by default.'); // Tests if the language field cannot be rearranged on the manage fields tab. $this->drupalGet('admin/structure/types/manage/article/fields'); @@ -64,9 +64,9 @@ class NodeTypeInitialLanguageTest extends NodeTestBase { $this->drupalPost('admin/config/regional/language', $edit, t('Save configuration')); // Tests the initial language after changing the site default language. - // First unhide the language selector + // First unhide the language selector. $edit = array( - 'node_type_language_hidden' => FALSE, + 'language_configuration[language_hidden]' => FALSE, ); $this->drupalPost('admin/structure/types/manage/article', $edit, t('Save content type')); $this->drupalGet('node/add/article'); @@ -87,7 +87,7 @@ class NodeTypeInitialLanguageTest extends NodeTestBase { // Changes the inital language settings. $edit = array( - 'node_type_language_default' => 'en', + 'language_configuration[langcode]' => 'en', ); $this->drupalPost('admin/structure/types/manage/article', $edit, t('Save content type')); $this->drupalGet('node/add/article'); diff --git a/core/modules/node/node.install b/core/modules/node/node.install index 5727129..a26026e 100644 --- a/core/modules/node/node.install +++ b/core/modules/node/node.install @@ -465,11 +465,10 @@ function node_uninstall() { ->condition('name', 'node_options_' . $type) ->condition('name', 'node_submitted_' . $type) ->condition('name', 'node_permissions_' . $type) - ->condition('name', 'node_type_language_default_' . $type) - ->condition('name', 'node_type_language_hidden_' . $type) ->condition('name', 'node_type_language_translation_enabled_' . $type) ) ->execute(); + config('language.settings')->clear('node. ' . $type . '.language.default_configuration')->save(); } // Delete node search ranking variables. @@ -601,6 +600,21 @@ function node_update_8004() { } /** + * Move the language default values to config. + */ +function node_update_8005() { + $types = db_query('SELECT type FROM {node_type}')->fetchCol(); + foreach ($types as $type) { + $language_default = update_variable_get('node_type_language_default_' . $type, NULL); + $language_hidden = update_variable_get('node_type_language_hidden_' . $type, NULL); + if (isset($language_default) || isset($language_hidden)) { + $values = array('langcode' => $language_default, 'language_hidden' => $language_hidden); + config('language.settings')->set('node. ' . $type . '.language.default_configuration', $values)->save(); + } + } +} + +/** * @} End of "addtogroup updates-7.x-to-8.x" * The next series of updates should start at 9000. */ diff --git a/core/modules/node/node.module b/core/modules/node/node.module index 8a41887..3b702bc 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -678,13 +678,16 @@ function node_field_extra_fields() { // Add also the 'language' select if Language module is enabled and the // bundle has multilingual support. // Visibility of the ordering of the language selector is the same as on the - // node/add form, i.e. node_type_language_hidden_TYPE variable. - if ($module_language_enabled && !variable_get('node_type_language_hidden_' . $bundle->type, TRUE)) { - $extra['node'][$bundle->type]['form']['language'] = array( - 'label' => t('Language'), - 'description' => $description, - 'weight' => 0, - ); + // node/add form. + if ($module_language_enabled) { + $configuration = language_get_default_configuration('node', $bundle->type); + if (!$configuration['language_hidden']) { + $extra['node'][$bundle->type]['form']['language'] = array( + 'label' => t('Language'), + 'description' => $description, + 'weight' => 0, + ); + } } $extra['node'][$bundle->type]['display']['language'] = array( 'label' => t('Language'), @@ -698,47 +701,6 @@ function node_field_extra_fields() { } /** - * Get the default language for a node type. - * - * @param string $node_type - * The type of node. - * - * @return string - * The language code of the node type's default langcode. - */ -function node_type_get_default_langcode($node_type) { - $default_value = variable_get('node_type_language_default_' . $node_type, 'site_default'); - - $language_interface = language(LANGUAGE_TYPE_INTERFACE); - - if ($default_value == LANGUAGE_NOT_SPECIFIED) { - return LANGUAGE_NOT_SPECIFIED; - } - - switch ($default_value) { - case 'site_default': - $default_value = language_default()->langcode; - break; - - case 'current_interface': - $default_value = $language_interface->langcode; - break; - - case 'authors_default': - global $user; - if (!empty($user->preferred_langcode)) { - $default_value = $user->preferred_langcode; - } - else { - $default_value = $language_interface->langcode; - } - break; - } - - return $default_value; -} - -/** * Deletes a node type from the database. * * @param $name diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc index 12437e1..59a6754 100644 --- a/core/modules/node/node.pages.inc +++ b/core/modules/node/node.pages.inc @@ -88,11 +88,12 @@ function node_add($node_type) { global $user; $type = $node_type->type; + $langcode = module_invoke('language', 'get_default_langcode', 'node', $type); $node = entity_create('node', array( 'uid' => $user->uid, 'name' => (isset($user->name) ? $user->name : ''), 'type' => $type, - 'langcode' => node_type_get_default_langcode($type) + 'langcode' => $langcode ? $langcode : language_default()->langcode, )); drupal_set_title(t('Create @name', array('@name' => $node_type->name)), PASS_THROUGH); $output = entity_get_form($node); diff --git a/core/modules/path/lib/Drupal/path/Tests/PathLanguageTest.php b/core/modules/path/lib/Drupal/path/Tests/PathLanguageTest.php index 691c537..e6fd10d 100644 --- a/core/modules/path/lib/Drupal/path/Tests/PathLanguageTest.php +++ b/core/modules/path/lib/Drupal/path/Tests/PathLanguageTest.php @@ -31,7 +31,7 @@ class PathLanguageTest extends PathTestBase { parent::setUp(); // Create and login user. - $this->web_user = $this->drupalCreateUser(array('edit any page content', 'create page content', 'administer url aliases', 'create url aliases', 'administer languages', 'translate all content', 'access administration pages')); + $this->web_user = $this->drupalCreateUser(array('edit any page content', 'create page content', 'administer url aliases', 'create url aliases', 'administer languages', 'translate all content', 'access administration pages', 'administer content types')); $this->drupalLogin($this->web_user); // Enable French language. @@ -50,7 +50,11 @@ class PathLanguageTest extends PathTestBase { */ function testAliasTranslation() { // Set 'page' content type to enable translation. - variable_set('node_type_language_hidden_page', FALSE); + $edit = array( + 'language_configuration[language_hidden]' => FALSE, + ); + $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type')); + $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), 'Basic page content type has been updated.'); variable_set('node_type_language_translation_enabled_page', TRUE); $english_node = $this->drupalCreateNode(array('type' => 'page')); diff --git a/core/modules/poll/lib/Drupal/poll/Tests/PollTranslateTest.php b/core/modules/poll/lib/Drupal/poll/Tests/PollTranslateTest.php index 4d9299a..d1ce358 100644 --- a/core/modules/poll/lib/Drupal/poll/Tests/PollTranslateTest.php +++ b/core/modules/poll/lib/Drupal/poll/Tests/PollTranslateTest.php @@ -54,7 +54,7 @@ class PollTranslateTest extends PollTestBase { // Set "Poll" content type to use multilingual support with translation. $this->drupalGet('admin/structure/types/manage/poll'); - $edit = array('node_type_language_hidden' => FALSE, 'node_type_language_translation_enabled' => TRUE); + $edit = array('language_configuration[language_hidden]' => FALSE, 'node_type_language_translation_enabled' => TRUE); $this->drupalPost('admin/structure/types/manage/poll', $edit, t('Save content type')); $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Poll')), 'Poll content type has been updated.'); diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationFormTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationFormTest.php index cf793c2..f518520 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationFormTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationFormTest.php @@ -86,7 +86,7 @@ class EntityTranslationFormTest extends WebTestBase { // Enable language selector. $this->drupalGet('admin/structure/types/manage/page'); - $edit = array('node_type_language_hidden' => FALSE, 'node_type_language_default' => LANGUAGE_NOT_SPECIFIED); + $edit = array('language_configuration[language_hidden]' => FALSE, 'language_configuration[langcode]' => LANGUAGE_NOT_SPECIFIED); $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type')); $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.')); diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php index c7ee415..77d0874 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/TermFormController.php @@ -41,12 +41,13 @@ class TermFormController extends EntityFormController { '#format' => $term->format, '#weight' => 0, ); - + $language_configuration = module_invoke('language', 'get_default_configuration', 'vocabulary', $vocabulary->machine_name); $form['langcode'] = array( '#type' => 'language_select', '#title' => t('Language'), '#languages' => LANGUAGE_ALL, '#default_value' => $term->langcode, + '#access' => !is_null($language_configuration['language_hidden']) && !$language_configuration['language_hidden'], ); $form['vocabulary_machine_name'] = array( diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermLanguageTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermLanguageTest.php index f64cf58..b609dfe 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermLanguageTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermLanguageTest.php @@ -33,21 +33,23 @@ class TermLanguageTest extends TaxonomyTestBase { // Create a vocabulary to which the terms will be assigned. $this->vocabulary = $this->createVocabulary(); + + // Add some custom languages. + foreach (array('aa', 'bb', 'cc') as $language_code) { + $language = new Language(array( + 'langcode' => $language_code, + 'name' => $this->randomName(), + )); + language_save($language); + } } function testTermLanguage() { - // Add first some custom languages. - $language = new Language(array( - 'langcode' => 'aa', - 'name' => $this->randomName(), - )); - language_save($language); - - $language = new Language(array( - 'langcode' => 'bb', - 'name' => $this->randomName(), - )); - language_save($language); + // Configure the vocabulary to not hide the language selector. + $edit = array( + 'default_language[language_hidden]' => FALSE, + ); + $this->drupalPost('admin/structure/taxonomy/' . $this->vocabulary->machine_name . '/edit', $edit, t('Save')); // Add a term. $this->drupalGet('admin/structure/taxonomy/' . $this->vocabulary->machine_name . '/add'); @@ -75,4 +77,43 @@ class TermLanguageTest extends TaxonomyTestBase { $this->drupalGet('taxonomy/term/' . $term->tid . '/edit'); $this->assertOptionSelected('edit-langcode', $edit['langcode'], t('The term language was correctly selected.')); } + + function testDefaultTermLanguage() { + // Configure the vocabulary to not hide the language selector, and make the + // default language of the terms fixed. + $edit = array( + 'default_language[langcode]' => 'bb', + 'default_language[language_hidden]' => FALSE, + ); + $this->drupalPost('admin/structure/taxonomy/' . $this->vocabulary->machine_name . '/edit', $edit, t('Save')); + $this->drupalGet('admin/structure/taxonomy/' . $this->vocabulary->machine_name . '/add'); + $this->assertOptionSelected('edit-langcode', 'bb'); + + // Make the default language of the terms to be the current interface. + $edit = array( + 'default_language[langcode]' => 'current_interface', + 'default_language[language_hidden]' => FALSE, + ); + $this->drupalPost('admin/structure/taxonomy/' . $this->vocabulary->machine_name . '/edit', $edit, t('Save')); + $this->drupalGet('aa/admin/structure/taxonomy/' . $this->vocabulary->machine_name . '/add'); + $this->assertOptionSelected('edit-langcode', 'aa'); + $this->drupalGet('bb/admin/structure/taxonomy/' . $this->vocabulary->machine_name . '/add'); + $this->assertOptionSelected('edit-langcode', 'bb'); + + // Change the default language of the site and check if the default terms + // language is still correctly selected. + $old_default = language_default(); + $old_default->default = FALSE; + language_save($old_default); + $new_default = language_load('cc'); + $new_default->default = TRUE; + language_save($new_default); + $edit = array( + 'default_language[langcode]' => 'site_default', + 'default_language[language_hidden]' => FALSE, + ); + $this->drupalPost('admin/structure/taxonomy/' . $this->vocabulary->machine_name . '/edit', $edit, t('Save')); + $this->drupalGet('admin/structure/taxonomy/' . $this->vocabulary->machine_name . '/add'); + $this->assertOptionSelected('edit-langcode', 'cc'); + } } diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyLanguageTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyLanguageTest.php index f4368b7..f61b9e5 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyLanguageTest.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/VocabularyLanguageTest.php @@ -30,10 +30,8 @@ class VocabularyLanguageTest extends TaxonomyTestBase { // Create an administrative user. $this->admin_user = $this->drupalCreateUser(array('administer taxonomy')); $this->drupalLogin($this->admin_user); - } - function testVocabularyLanguage() { - // Add first some custom languages. + // Add some custom languages. $language = new Language(array( 'langcode' => 'aa', 'name' => $this->randomName(), @@ -45,8 +43,14 @@ class VocabularyLanguageTest extends TaxonomyTestBase { 'name' => $this->randomName(), )); language_save($language); + } + /** + * Tests language settings for vocabularies. + */ + function testVocabularyLanguage() { $this->drupalGet('admin/structure/taxonomy/add'); + // Check that we have the language selector available. $this->assertField('edit-langcode', t('The language selector field was found on the page')); @@ -70,4 +74,67 @@ class VocabularyLanguageTest extends TaxonomyTestBase { $this->drupalGet('admin/structure/taxonomy/' . $machine_name . '/edit'); $this->assertOptionSelected('edit-langcode', $edit['langcode'], t('The vocabulary language was correctly selected.')); } + + /** + * Tests term language settings for vocabulary terms are saved and updated. + */ + function testVocabularyDefaultLanguageForTerms() { + // Add a new vocabulary and check that the default language settings are for + // the terms are saved. + $edit = array( + 'name' => $this->randomName(), + 'machine_name' => drupal_strtolower($this->randomName()), + 'default_language[langcode]' => 'bb', + 'default_language[language_hidden]' => FALSE, + ); + $machine_name = $edit['machine_name']; + $this->drupalPost('admin/structure/taxonomy/add', $edit, t('Save')); + + // Check that the vocabulary was actually created. + $this->drupalGet('admin/structure/taxonomy/' . $edit['machine_name'] . '/edit'); + $this->assertResponse(200, 'The vocabulary has been created.'); + + // Check that the language settings were saved. + $language_settings = language_get_default_configuration('vocabulary', $edit['machine_name']); + $this->assertEqual($language_settings['langcode'], 'bb'); + $this->assertEqual($language_settings['language_hidden'], FALSE); + + // Check that the correct options are selected in the interface. + $this->assertOptionSelected('edit-default-language-langcode', 'bb', 'The correct default language for the terms of this vocabulary is selected.'); + $this->assertNoFieldChecked('edit-default-language-language-hidden', 'Hide language selection option is not checked.'); + + // Edit the vocabulary and check that the new settings are updated. + $edit = array( + 'default_language[langcode]' => 'aa', + 'default_language[language_hidden]' => TRUE, + ); + $this->drupalPost('admin/structure/taxonomy/' . $machine_name . '/edit', $edit, t('Save')); + + // And check again the settings and also the interface. + $language_settings = language_get_default_configuration('vocabulary', $machine_name); + $this->assertEqual($language_settings['langcode'], 'aa'); + $this->assertEqual($language_settings['language_hidden'], TRUE); + + $this->drupalGet('admin/structure/taxonomy/' . $machine_name . '/edit'); + $this->assertOptionSelected('edit-default-language-langcode', 'aa', 'The correct default language for the terms of this vocabulary is selected.'); + $this->assertFieldChecked('edit-default-language-language-hidden', 'Hide language selection option is not checked.'); + + // Check that, if the machine name of the vocabulary is changed, then the + // settings are applied on the new machine name. + $edit = array( + 'machine_name' => $machine_name . '_new', + 'default_language[langcode]' => 'authors_default', + 'default_language[language_hidden]' => TRUE, + ); + $new_machine_name = $edit['machine_name']; + $this->drupalPost('admin/structure/taxonomy/' . $machine_name . '/edit', $edit, t('Save')); + + // Check that the old settings are empty. + $old_settings = config('language.settings')->get(language_get_default_configuration_settings_path('vocabulary', $machine_name)); + $this->assertNull($old_settings, 'The old vocabulary settings were deleted.'); + // Check that we have the new settings. + $new_settings = language_get_default_configuration('vocabulary', $new_machine_name); + $this->assertEqual($new_settings['langcode'], 'authors_default'); + $this->assertEqual($new_settings['language_hidden'], TRUE); + } } diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyFormController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyFormController.php index bdeea4c..450cd55 100644 --- a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyFormController.php +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyFormController.php @@ -44,12 +44,31 @@ class VocabularyFormController extends EntityFormController { '#title' => t('Description'), '#default_value' => $vocabulary->description, ); + + // $form['langcode'] is not wrapped in an if (module_exists('language')) + // check because the language_select form element works also without the + // language module being installed. + // http://drupal.org/node/1749954 documents the new element. $form['langcode'] = array( '#type' => 'language_select', - '#title' => t('Language'), + '#title' => t('Vocabulary language'), '#languages' => LANGUAGE_ALL, '#default_value' => $vocabulary->langcode, ); + if (module_exists('language')) { + $form['default_terms_language'] = array( + '#type' => 'fieldset', + '#title' => t('Terms language'), + ); + $form['default_terms_language']['default_language'] = array( + '#type' => 'language_configuration', + '#entity_information' => array( + 'entity_type' => 'vocabulary', + 'bundle' => $vocabulary->machine_name, + ), + '#default_value' => language_get_default_configuration('vocabulary', $vocabulary->machine_name), + ); + } // Set the hierarchy to "multiple parents" by default. This simplifies the // vocabulary form and standardizes the term form. $form['hierarchy'] = array( @@ -72,6 +91,12 @@ class VocabularyFormController extends EntityFormController { if (empty($form_state['confirm_delete'])) { $actions = parent::actions($form, $form_state); array_unshift($actions['delete']['#submit'], array($this, 'submit')); + // Add the language configuration submit handler. This is needed because + // the submit button has custom submit handlers. + if (module_exists('language')) { + array_unshift($actions['submit']['#submit'],'language_configuration_element_submit'); + array_unshift($actions['submit']['#submit'], array($this, 'languageConfigurationSubmit')); + } return $actions; } else { @@ -100,6 +125,22 @@ class VocabularyFormController extends EntityFormController { } /** + * Submit handler to update the bundle for the default language configuration. + */ + public function languageConfigurationSubmit(array &$form, array &$form_state) { + $vocabulary = $this->getEntity($form_state); + // Delete the old language settings for the vocabulary, if the machine name + // is changed. + if ($vocabulary && isset($vocabulary->machine_name) && $vocabulary->machine_name != $form_state['values']['machine_name']) { + language_clear_default_configuration('vocabulary', $vocabulary->machine_name); + } + // Since the machine name is not known yet, and it can be changed anytime, + // we have to also update the bundle property for the default language + // configuration in order to have the correct bundle value. + $form_state['language']['default_language']['bundle'] = $form_state['values']['machine_name']; + } + + /** * Overrides Drupal\Core\Entity\EntityFormController::submit(). */ public function submit(array $form, array &$form_state) { diff --git a/core/modules/taxonomy/taxonomy.admin.inc b/core/modules/taxonomy/taxonomy.admin.inc index ecef0b5..ffa03ab 100644 --- a/core/modules/taxonomy/taxonomy.admin.inc +++ b/core/modules/taxonomy/taxonomy.admin.inc @@ -108,7 +108,6 @@ function taxonomy_vocabulary_add() { $vocabulary = entity_create('taxonomy_vocabulary', array( // Default the new vocabulary to the site's default language. This is the // most likely default value until we have better flexible settings. - // @todo See http://drupal.org/node/258785 and followups. 'langcode' => language_default()->langcode, )); return entity_get_form($vocabulary); @@ -522,6 +521,9 @@ function theme_taxonomy_overview_terms($variables) { */ function taxonomy_term_add($vocabulary) { $term = entity_create('taxonomy_term', array('vid' => $vocabulary->vid, 'vocabulary_machine_name' => $vocabulary->machine_name)); + if (module_exists('language')) { + $term->langcode = language_get_default_langcode('vocabulary', $vocabulary->machine_name); + } return entity_get_form($term); } diff --git a/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php b/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php index a9fae77..fccb453 100644 --- a/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php +++ b/core/modules/translation/lib/Drupal/translation/Tests/TranslationTest.php @@ -51,7 +51,7 @@ class TranslationTest extends WebTestBase { // Set "Basic page" content type to use multilingual support with // translation. $this->drupalGet('admin/structure/types/manage/page'); - $edit = array('node_type_language_hidden' => FALSE, 'node_type_language_translation_enabled' => TRUE); + $edit = array('language_configuration[language_hidden]' => FALSE, 'node_type_language_translation_enabled' => TRUE); $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type')); $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.')); @@ -230,7 +230,7 @@ class TranslationTest extends WebTestBase { // Disable translation support to check that the language switcher is left // untouched only for new nodes. $this->drupalLogin($this->admin_user); - $edit = array('node_type_language_hidden' => TRUE, 'node_type_language_translation_enabled' => FALSE); + $edit = array('language_configuration[language_hidden]' => TRUE, 'node_type_language_translation_enabled' => FALSE); $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type')); $this->drupalLogin($this->translator); diff --git a/core/modules/translation/translation.module b/core/modules/translation/translation.module index bf1e528..e7f22fd 100644 --- a/core/modules/translation/translation.module +++ b/core/modules/translation/translation.module @@ -173,7 +173,7 @@ function translation_form_node_type_form_alter(&$form, &$form_state) { * and language selector is not hidden, translation cannot be enabled. */ function translation_node_type_language_translation_enabled_validate($element, &$form_state, $form) { - if (language_is_locked($form_state['values']['node_type_language_default']) && $form_state['values']['node_type_language_hidden'] && $form_state['values']['node_type_language_translation_enabled']) { + if (language_is_locked($form_state['values']['language_configuration']['langcode']) && $form_state['values']['language_configuration']['language_hidden'] && $form_state['values']['node_type_language_translation_enabled']) { foreach (language_list(LANGUAGE_LOCKED) as $language) { $locked_languages[] = $language->name; }