Issue #1280996 by tarmstrong, vasi1186, fastangel, dawehner, tobiasb: New language_select() element type for form API.

8.0.x
webchick 2012-08-22 01:31:54 +02:00
parent 7b757ff47e
commit 6cdb69e106
13 changed files with 429 additions and 66 deletions

View File

@ -102,3 +102,22 @@ function language_schema() {
);
return $schema;
}
/**
* Implements hook_enable().
*/
function language_enable() {
// Update the language count, if the module was disabled before, the
// language_count variable was forced to 1.
language_update_count();
}
/**
* Implements hook_disable().
*/
function language_disable() {
// Force the language_count variable to be 1, so that the when checking if the
// site is multilingual (for example in language_multilingual()), the result
// will be FALSE, because the language module is disabled.
variable_set('language_count', 1);
}

View File

@ -157,6 +157,48 @@ function language_theme() {
);
}
/**
* Implements hook_element_info_alter().
*/
function language_element_info_alter(&$type) {
// Alter the language_select element so that it will be rendered like a select
// field.
if (isset($type['language_select'])) {
if (!isset($type['language_select']['#process'])) {
$type['language_select']['#process'] = array();
}
if (!isset($type['language_select']['#theme_wrappers'])) {
$type['language_select']['#theme_wrappers'] = array();
}
$type['language_select']['#process'] = array_merge($type['language_select']['#process'], array('language_process_language_select', 'form_process_select', 'ajax_process_form'));
$type['language_select']['#theme'] = 'select';
$type['language_select']['#theme_wrappers'] = array_merge($type['language_select']['#theme_wrappers'], array('form_element'));
$type['language_select']['#languages'] = LANGUAGE_CONFIGURABLE;
$type['language_select']['#multiple'] = FALSE;
}
}
/**
* Processes a language select list form element.
*
* @param array $element
* The form element to process.
*
* @return array $element
* The processed form element.
*/
function language_process_language_select($element) {
// Don't set the options if another module(translation for example) already
// set the options.
if (!isset($element['#options'])) {
$element['#options'] = array();
foreach (language_list($element['#languages']) as $langcode => $language) {
$element['#options'][$langcode] = $language->locked ? t('- @name -', array('@name' => $language->name)) : $language->name;
}
}
return $element;
}
/**
* API function to add or update a language.
*
@ -197,7 +239,7 @@ function language_save($language) {
}
// Update language count based on unlocked language count.
variable_set('language_count', db_query('SELECT COUNT(langcode) FROM {language} WHERE locked = 0')->fetchField());
language_update_count();
// Kill the static cache in language_list().
drupal_static_reset('language_list');
@ -205,6 +247,17 @@ function language_save($language) {
return $language;
}
/**
* Updates the language_count variable.
*
* This is used to check if a site is multilingual or not.
*
* @see language_multilingual()
*/
function language_update_count() {
variable_set('language_count', db_query('SELECT COUNT(langcode) FROM {language} WHERE locked = 0')->fetchField());
}
/**
* Delete a language.
*
@ -225,7 +278,7 @@ function language_delete($langcode) {
->condition('langcode', $language->langcode)
->execute();
variable_set('language_count', variable_get('language_count', 1) - 1);
language_update_count();
drupal_static_reset('language_list');

View File

@ -97,28 +97,13 @@ class NodeFormController extends EntityFormController {
$form['title']['#weight'] = -5;
}
if (module_exists('language')) {
$languages = language_list(LANGUAGE_ALL);
$language_options = array();
foreach ($languages as $langcode => $language) {
// Make locked languages appear special in the list.
$language_options[$langcode] = $language->locked ? t('- @name -', array('@name' => $language->name)) : $language->name;
}
$form['langcode'] = array(
'#type' => 'select',
'#title' => t('Language'),
'#default_value' => $node->langcode,
'#options' => $language_options,
'#access' => !variable_get('node_type_language_hidden_' . $node->type, TRUE),
);
}
else {
$form['langcode'] = array(
'#type' => 'value',
'#value' => $node->langcode,
);
}
$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),
);
$form['additional_settings'] = array(
'#type' => 'vertical_tabs',

View File

@ -0,0 +1,120 @@
<?php
/**
* @file
* Definition of Drupal\system\Tests\Form\LanguageSelectElementTest.
*/
namespace Drupal\system\Tests\Form;
use Drupal\simpletest\WebTestBase;
use Drupal\Core\Language\Language;
/**
* Functional tests for the language select form element.
*/
class LanguageSelectElementTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('form_test', 'language');
public static function getInfo() {
return array(
'name' => 'Language select form element',
'description' => 'Checks that the language select form element prints and submits the right options.',
'group' => 'Form API',
);
}
/**
* Tests that the options printed by the language select element are correct.
*/
function testLanguageSelectElementOptions() {
// Add some languages.
$language = (object) array(
'langcode' => 'aaa',
'name' => $this->randomName(),
);
language_save($language);
$language = (object) array(
'langcode' => 'bbb',
'name' => $this->randomName(),
);
language_save($language);
$this->drupalGet('form-test/language_select');
// Check that the language fields were rendered on the page.
$ids = array('edit-languages-all' => LANGUAGE_ALL,
'edit-languages-configurable' => LANGUAGE_CONFIGURABLE,
'edit-languages-locked' => LANGUAGE_LOCKED,
'edit-languages-config-and-locked' => LANGUAGE_CONFIGURABLE | LANGUAGE_LOCKED);
foreach ($ids as $id => $flags) {
$this->assertField($id, t('The @id field was found on the page.', array('@id' => $id)));
$options = array();
foreach (language_list($flags) as $langcode => $language) {
$options[$langcode] = $language->locked ? t('- @name -', array('@name' => $language->name)) : $language->name;
}
$this->_testLanguageSelectElementOptions($id, $options);
}
// Test that the #options were not altered by #languages.
$this->assertField('edit-language-custom-options', t('The @id field was found on the page.', array('@id' => 'edit-language-custom-options')));
$this->_testLanguageSelectElementOptions('edit-language-custom-options', array('opt1' => 'First option', 'opt2' => 'Second option', 'opt3' => 'Third option'));
}
/**
* Tests the case when the language select elements should not be printed.
*
* This happens when the language module is disabled.
*/
function testHiddenLanguageSelectElement() {
// Disable the language module, so that the language select field will not
// be rendered.
module_disable(array('language'));
$this->drupalGet('form-test/language_select');
// Check that the language fields were rendered on the page.
$ids = array('edit-languages-all', 'edit-languages-configurable', 'edit-languages-locked', 'edit-languages-config-and-locked');
foreach ($ids as $id) {
$this->assertNoField($id, t('The @id field was not found on the page.', array('@id' => $id)));
}
// Check that the submitted values were the default values of the language
// field elements.
$edit = array();
$this->drupalPost(NULL, $edit, t('Submit'));
$values = drupal_json_decode($this->drupalGetContent());
$this->assertEqual($values['languages_all'], 'xx');
$this->assertEqual($values['languages_configurable'], 'en');
$this->assertEqual($values['languages_locked'], LANGUAGE_NOT_SPECIFIED);
$this->assertEqual($values['languages_config_and_locked'], 'dummy_value');
$this->assertEqual($values['language_custom_options'], 'opt2');
}
/**
* Helper function to check the options of a language select form element.
*
* @param string $id
* The id of the language select element to check.
*
* @param array $options
* An array with options to compare with.
*/
protected function _testLanguageSelectElementOptions($id, $options) {
// Check that the options in the language field are exactly the same,
// including the order, as the languages sent as a parameter.
$elements = $this->xpath("//select[@id='" . $id . "']");
$count = 0;
foreach ($elements[0]->option as $option) {
$count++;
$option_title = current($options);
$this->assertEqual((string) $option, $option_title);
next($options);
}
$this->assertEqual($count, count($options), t('The number of languages and the number of options shown by the language element are the same: @languages languages, @number options', array('@languages' => count($options), '@number' => $count)));
}
}

View File

@ -504,6 +504,10 @@ function system_element_info() {
'#theme' => 'select',
'#theme_wrappers' => array('form_element'),
);
$types['language_select'] = array(
'#input' => TRUE,
'#default_value' => LANGUAGE_NOT_SPECIFIED,
);
$types['weight'] = array(
'#input' => TRUE,
'#delta' => 10,

View File

@ -133,6 +133,12 @@ function form_test_menu() {
'page arguments' => array('form_test_select'),
'access callback' => TRUE,
);
$items['form-test/language_select'] = array(
'title' => t('Language Select'),
'page callback' => 'drupal_get_form',
'page arguments' => array('form_test_language_select'),
'access callback' => TRUE,
);
$items['form-test/placeholder-text'] = array(
'title' => 'Placeholder',
'page callback' => 'drupal_get_form',
@ -1223,6 +1229,42 @@ function form_test_select($form, &$form_state) {
return $form;
}
/**
* Builds a form to test the language select form element.
*/
function form_test_language_select() {
$form['#submit'] = array('_form_test_submit_values_json');
$form['languages_all'] = array(
'#type' => 'language_select',
'#languages' => LANGUAGE_ALL,
'#default_value' => 'xx',
);
$form['languages_configurable'] = array(
'#type' => 'language_select',
'#languages' => LANGUAGE_CONFIGURABLE,
'#default_value' => 'en',
);
$form['languages_locked'] = array(
'#type' => 'language_select',
'#languages' => LANGUAGE_LOCKED,
);
$form['languages_config_and_locked'] = array(
'#type' => 'language_select',
'#languages' => LANGUAGE_CONFIGURABLE | LANGUAGE_LOCKED,
'#default_value' => 'dummy_value',
);
$form['language_custom_options'] = array(
'#type' => 'language_select',
'#languages' => LANGUAGE_CONFIGURABLE | LANGUAGE_LOCKED,
'#options' => array('opt1' => 'First option', 'opt2' => 'Second option', 'opt3' => 'Third option'),
'#default_value' => 'opt2',
);
$form['submit'] = array('#type' => 'submit', '#value' => 'Submit');
return $form;
}
/**
* Builds a form to test #type 'number' and 'range' validation.
*

View File

@ -42,6 +42,13 @@ class TermFormController extends EntityFormController {
'#weight' => 0,
);
$form['langcode'] = array(
'#type' => 'language_select',
'#title' => t('Language'),
'#languages' => LANGUAGE_ALL,
'#default_value' => $term->langcode,
);
$form['vocabulary_machine_name'] = array(
'#type' => 'value',
'#value' => isset($term->vocabulary_machine_name) ? $term->vocabulary_machine_name : $vocabulary->name,

View File

@ -0,0 +1,76 @@
<?php
/**
* @file
* Definition of Drupal\taxonomy\Tests\TermLanguageTest.
*/
namespace Drupal\taxonomy\Tests;
/**
* Tests for the language feature on taxonomy terms.
*/
class TermLanguageTest extends TaxonomyTestBase {
public static $modules = array('language');
public static function getInfo() {
return array(
'name' => 'Taxonomy term language',
'description' => 'Tests the language functionality for the taxonomy terms.',
'group' => 'Taxonomy',
);
}
function setUp() {
parent::setUp();
// Create an administrative user.
$this->admin_user = $this->drupalCreateUser(array('administer taxonomy'));
$this->drupalLogin($this->admin_user);
// Create a vocabulary to which the terms will be assigned.
$this->vocabulary = $this->createVocabulary();
}
function testTermLanguage() {
// Add first some custom languages.
$language = (object) array(
'langcode' => 'aa',
'name' => $this->randomName(),
);
language_save($language);
$language = (object) array(
'langcode' => 'bb',
'name' => $this->randomName(),
);
language_save($language);
// Add a term.
$this->drupalGet('admin/structure/taxonomy/' . $this->vocabulary->machine_name . '/add');
// Check that we have the language selector.
$this->assertField('edit-langcode', t('The language selector field was found on the page'));
// Submit the term.
$edit = array(
'name' => $this->randomName(),
'langcode' => 'aa',
);
$this->drupalPost(NULL, $edit, t('Save'));
$terms = taxonomy_term_load_multiple_by_name($edit['name']);
$term = reset($terms);
$this->assertEqual($term->langcode, $edit['langcode']);
// Check if on the edit page the language is correct.
$this->drupalGet('taxonomy/term/' . $term->tid . '/edit');
$this->assertOptionSelected('edit-langcode', $edit['langcode'], t('The term language was correctly selected.'));
// Change the language of the term.
$edit['langcode'] = 'bb';
$this->drupalPost('taxonomy/term/' . $term->tid . '/edit', $edit, t('Save'));
// Check again that on the edit page the language is correct.
$this->drupalGet('taxonomy/term/' . $term->tid . '/edit');
$this->assertOptionSelected('edit-langcode', $edit['langcode'], t('The term language was correctly selected.'));
}
}

View File

@ -0,0 +1,71 @@
<?php
/**
* @file
* Definition of Drupal\taxonomy\Tests\VocabularyLanguageTest.
*/
namespace Drupal\taxonomy\Tests;
/**
* Tests for the language feature on vocabularies.
*/
class VocabularyLanguageTest extends TaxonomyTestBase {
public static $modules = array('language');
public static function getInfo() {
return array(
'name' => 'Vocabulary language',
'description' => 'Tests the language functionality for vocabularies.',
'group' => 'Taxonomy',
);
}
function setUp() {
parent::setUp();
// Create an administrative user.
$this->admin_user = $this->drupalCreateUser(array('administer taxonomy'));
$this->drupalLogin($this->admin_user);
}
function testVocabularyLanguage() {
// Add first some custom languages.
$language = (object) array(
'langcode' => 'aa',
'name' => $this->randomName(),
);
language_save($language);
$language = (object) array(
'langcode' => 'bb',
'name' => $this->randomName(),
);
language_save($language);
$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'));
// Create the vocabulary.
$machine_name = drupal_strtolower($this->randomName());
$edit['name'] = $this->randomName();
$edit['description'] = $this->randomName();
$edit['langcode'] = 'aa';
$edit['machine_name'] = $machine_name;
$this->drupalPost(NULL, $edit, t('Save'));
// Check the language on the edit page.
$this->drupalGet('admin/structure/taxonomy/' . $machine_name . '/edit');
$this->assertOptionSelected('edit-langcode', $edit['langcode'], t('The vocabulary language was correctly selected.'));
// Change the language and save again.
$edit['langcode'] = 'bb';
$this->drupalPost(NULL, $edit, t('Save'));
// Check again the language on the edit page.
$this->drupalGet('admin/structure/taxonomy/' . $machine_name . '/edit');
$this->assertOptionSelected('edit-langcode', $edit['langcode'], t('The vocabulary language was correctly selected.'));
}
}

View File

@ -44,6 +44,12 @@ class VocabularyFormController extends EntityFormController {
'#title' => t('Description'),
'#default_value' => $vocabulary->description,
);
$form['langcode'] = array(
'#type' => 'language_select',
'#title' => t('Language'),
'#languages' => LANGUAGE_ALL,
'#default_value' => $vocabulary->langcode,
);
// Set the hierarchy to "multiple parents" by default. This simplifies the
// vocabulary form and standardizes the term form.
$form['hierarchy'] = array(

View File

@ -203,45 +203,26 @@ abstract class AccountFormController extends EntityFormController {
$form['#validate'][] = 'user_validate_picture';
if (module_exists('language') && language_multilingual()) {
$languages = language_list();
$user_preferred_language = $register ? $language_interface : user_preferred_language($account);
// If the user is being created, we set the user language to the page language.
$user_preferred_language = $register ? $language_interface : user_preferred_language($account);
// Is default the interface language?
include_once DRUPAL_ROOT . '/core/includes/language.inc';
$interface_language_is_default = language_negotiation_method_get_first(LANGUAGE_TYPE_INTERFACE) != LANGUAGE_NEGOTIATION_DEFAULT;
$form['language'] = array(
'#type' => language_multilingual() ? 'fieldset' : 'container',
'#title' => t('Language settings'),
// Display language selector when either creating a user on the admin
// interface or editing a user account.
'#access' => !$register || user_access('administer users'),
);
$names = array();
foreach ($languages as $langcode => $item) {
$names[$langcode] = $item->name;
}
// Is default the interface language?
$interface_language_is_default = language_negotiation_method_get_first(LANGUAGE_TYPE_INTERFACE) != LANGUAGE_NEGOTIATION_DEFAULT;
$form['language'] = array(
'#type' => 'fieldset',
'#title' => t('Language settings'),
// Display language selector when either creating a user on the admin
// interface or editing a user account.
'#access' => !$register || user_access('administer users'),
);
$form['language']['preferred_langcode'] = array(
'#type' => (count($names) <= 5 ? 'radios' : 'select'),
'#title' => t('Language'),
'#default_value' => $user_preferred_language->langcode,
'#options' => $names,
'#description' => $interface_language_is_default ? t("This account's preferred language for e-mails and site presentation.") : t("This account's preferred language for e-mails."),
);
}
else {
$form['language'] = array(
'#type' => 'container',
);
$form['language']['preferred_langcode'] = array(
'#type' => 'value',
'#value' => language_default()->langcode,
);
}
$form['language']['preferred_langcode'] = array(
'#type' => 'language_select',
'#title' => t('Language'),
'#languages' => LANGUAGE_CONFIGURABLE,
'#default_value' => $user_preferred_language->langcode,
'#description' => $interface_language_is_default ? t("This account's preferred language for e-mails and site presentation.") : t("This account's preferred language for e-mails."),
);
// User entities contain both a langcode property (for identifying the
// language of the entity data) and a preferred_langcode property (see

View File

@ -62,7 +62,7 @@ class UserLanguageCreationTest extends WebTestBase {
// Check if the language selector is available on admin/people/create and
// set to the currently active language.
$this->drupalGet($langcode . '/admin/people/create');
$this->assertFieldChecked("edit-preferred-langcode-$langcode", t('Global language set in the language selector.'));
$this->assertOptionSelected("edit-preferred-langcode", $langcode, t('Global language set in the language selector.'));
// Create a user with the admin/people/create form and check if the correct
// language is set.
@ -104,7 +104,7 @@ class UserLanguageCreationTest extends WebTestBase {
$this->drupalLogin($admin_user);
$this->drupalGet($user_edit);
$this->assertFieldChecked("edit-preferred-langcode-$langcode", t('Language selector is accessible and correct language is selected.'));
$this->assertOptionSelected("edit-preferred-langcode", $langcode, t('Language selector is accessible and correct language is selected.'));
// Set pass_raw so we can login the new user.
$user->pass_raw = $this->randomName(10);
@ -117,6 +117,6 @@ class UserLanguageCreationTest extends WebTestBase {
$this->drupalLogin($user);
$this->drupalGet($user_edit);
$this->assertFieldChecked("edit-preferred-langcode-$langcode", t('Language selector is accessible and correct language is selected.'));
$this->assertOptionSelected("edit-preferred-langcode", $langcode, t('Language selector is accessible and correct language is selected.'));
}
}

View File

@ -71,8 +71,7 @@ class UserLanguageTest extends WebTestBase {
// Ensure form was submitted successfully.
$this->assertText(t('The changes have been saved.'), t('Changes were saved.'));
// Check if language was changed.
$elements = $this->xpath('//input[@id=:id]', array(':id' => 'edit-preferred-langcode-' . $langcode));
$this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), t('Default language successfully updated.'));
$this->assertOptionSelected('edit-preferred-langcode', $langcode, t('Default language successfully updated.'));
$this->drupalLogout();
}