Commit eb9954ac authored by gdd's avatar gdd

Merge remote-tracking branch 'origin/8.x' into 8.x-file-config

parents d60c422c 6e431c53
......@@ -1723,7 +1723,8 @@ function format_plural($count, $singular, $plural, array $args = array(), array
// Get the plural index through the gettext formula.
$index = (function_exists('locale_get_plural')) ? locale_get_plural($count, isset($options['langcode']) ? $options['langcode'] : NULL) : -1;
// Backwards compatibility.
// If the index cannot be computed, use the plural as a fallback (which
// allows for most flexiblity with the replaceable @count value).
if ($index < 0) {
return t($plural, $args, $options);
}
......
......@@ -172,7 +172,7 @@ function _drupal_session_write($sid, $value) {
// For performance reasons, do not update the sessions table, unless
// $_SESSION has changed or more than 180 has passed since the last update.
if ($is_changed || REQUEST_TIME - $user->timestamp > variable_get('session_write_interval', 180)) {
if ($is_changed || !isset($user->timestamp) || REQUEST_TIME - $user->timestamp > variable_get('session_write_interval', 180)) {
// Either ssid or sid or both will be added from $key below.
$fields = array(
'uid' => $user->uid,
......@@ -199,6 +199,9 @@ function _drupal_session_write($sid, $value) {
}
}
}
elseif (variable_get('https', FALSE)) {
unset($key['ssid']);
}
db_merge('sessions')
->key($key)
......@@ -255,11 +258,17 @@ function drupal_session_initialize() {
// we lazily start sessions at the end of this request, and some
// processes (like drupal_get_token()) needs to know the future
// session ID in advance.
$GLOBALS['lazy_session'] = TRUE;
$user = drupal_anonymous_user();
// Less random sessions (which are much faster to generate) are used for
// anonymous users than are generated in drupal_session_regenerate() when
// a user becomes authenticated.
session_id(drupal_hash_base64(uniqid(mt_rand(), TRUE)));
if ($is_https && variable_get('https', FALSE)) {
$insecure_session_name = substr(session_name(), 1);
$session_id = drupal_hash_base64(uniqid(mt_rand(), TRUE));
$_COOKIE[$insecure_session_name] = $session_id;
}
}
date_default_timezone_set(drupal_get_user_timezone());
}
......@@ -291,7 +300,7 @@ function drupal_session_start() {
* If an anonymous user already have an empty session, destroy it.
*/
function drupal_session_commit() {
global $user;
global $user, $is_https;
if (!drupal_save_session()) {
// We don't have anything to do if we are not allowed to save the session.
......@@ -310,6 +319,12 @@ function drupal_session_commit() {
// started.
if (!drupal_session_started()) {
drupal_session_start();
if ($is_https && variable_get('https', FALSE)) {
$insecure_session_name = substr(session_name(), 1);
$params = session_get_cookie_params();
$expire = $params['lifetime'] ? REQUEST_TIME + $params['lifetime'] : 0;
setcookie($insecure_session_name, $_COOKIE[$insecure_session_name], $expire, $params['path'], $params['domain'], FALSE, $params['httponly']);
}
}
// Write the session data.
session_write_close();
......@@ -336,7 +351,7 @@ function drupal_session_regenerate() {
global $user, $is_https;
if ($is_https && variable_get('https', FALSE)) {
$insecure_session_name = substr(session_name(), 1);
if (isset($_COOKIE[$insecure_session_name])) {
if (!isset($GLOBALS['lazy_session']) && isset($_COOKIE[$insecure_session_name])) {
$old_insecure_session_id = $_COOKIE[$insecure_session_name];
}
$params = session_get_cookie_params();
......@@ -416,7 +431,10 @@ function _drupal_session_destroy($sid) {
// Unset the session cookies.
_drupal_session_delete_cookie(session_name());
if ($is_https) {
_drupal_session_delete_cookie(substr(session_name(), 1), TRUE);
_drupal_session_delete_cookie(substr(session_name(), 1), FALSE);
}
elseif (variable_get('https', FALSE)) {
_drupal_session_delete_cookie('S' . session_name(), TRUE);
}
}
......@@ -425,13 +443,17 @@ function _drupal_session_destroy($sid) {
*
* @param $name
* Name of session cookie to delete.
* @param $force_insecure
* Force cookie to be insecure.
* @param boolean $secure
* Force the secure value of the cookie.
*/
function _drupal_session_delete_cookie($name, $force_insecure = FALSE) {
if (isset($_COOKIE[$name])) {
function _drupal_session_delete_cookie($name, $secure = NULL) {
global $is_https;
if (isset($_COOKIE[$name]) || (!$is_https && $secure === TRUE)) {
$params = session_get_cookie_params();
setcookie($name, '', REQUEST_TIME - 3600, $params['path'], $params['domain'], !$force_insecure && $params['secure'], $params['httponly']);
if ($secure !== NULL) {
$params['secure'] = $secure;
}
setcookie($name, '', REQUEST_TIME - 3600, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
unset($_COOKIE[$name]);
}
}
......
......@@ -18,7 +18,7 @@ Drupal.behaviors.autocomplete = {
$input.parent()
.attr('role', 'application')
.append($('<span class="element-invisible" aria-live="assertive"></span>')
.attr('id', $input.attr('id') + '-autocomplete-aria-live')
.attr('id', $input[0].id + '-autocomplete-aria-live')
);
new Drupal.jsAC($input, acdb[uri]);
});
......@@ -30,9 +30,11 @@ Drupal.behaviors.autocomplete = {
* and closes the suggestions popup when doing so.
*/
Drupal.autocompleteSubmit = function () {
return $('#autocomplete').each(function () {
this.owner.hidePopup();
}).length == 0;
var $autocomplete = $('#autocomplete');
if ($autocomplete.length !== 0) {
$autocomplete[0].owner.hidePopup();
}
return $autocomplete.length === 0;
};
/**
......@@ -48,7 +50,6 @@ Drupal.jsAC = function ($input, db) {
.keydown(function (event) { return ac.onkeydown(this, event); })
.keyup(function (event) { ac.onkeyup(this, event); })
.blur(function () { ac.hidePopup(); ac.db.cancel(); });
};
/**
......@@ -99,10 +100,12 @@ Drupal.jsAC.prototype.onkeyup = function (input, e) {
return true;
default: // All other keys.
if (input.value.length > 0)
if (input.value.length > 0) {
this.populatePopup();
else
}
else {
this.hidePopup(e.keyCode);
}
return true;
}
};
......@@ -142,7 +145,8 @@ Drupal.jsAC.prototype.selectUp = function () {
* Highlights a suggestion.
*/
Drupal.jsAC.prototype.highlight = function (node) {
if (this.selected) {
// Unhighlights a suggestion for "keyup" and "keydown" events.
if (this.selected !== false) {
$(this.selected).removeClass('selected');
}
$(node).addClass('selected');
......@@ -164,7 +168,7 @@ Drupal.jsAC.prototype.unhighlight = function (node) {
*/
Drupal.jsAC.prototype.hidePopup = function (keycode) {
// Select item if the right key or mousebutton was pressed.
if (this.selected && ((keycode && keycode != 46 && keycode != 8 && keycode != 27) || !keycode)) {
if (this.selected && ((keycode && keycode !== 46 && keycode !== 8 && keycode !== 27) || !keycode)) {
this.input.value = $(this.selected).data('autocompleteValue');
}
// Hide popup.
......@@ -215,14 +219,16 @@ Drupal.jsAC.prototype.found = function (matches) {
// Prepare matches.
var ul = $('<ul></ul>');
var ac = this;
for (key in matches) {
$('<li></li>')
.html($('<div></div>').html(matches[key]))
.mousedown(function () { ac.select(this); })
.mouseover(function () { ac.highlight(this); })
.mouseout(function () { ac.unhighlight(this); })
.data('autocompleteValue', key)
.appendTo(ul);
for (var key in matches) {
if (matches.hasOwnProperty(key)) {
$('<li></li>')
.html($('<div></div>').html(matches[key]))
.mousedown(function () { ac.select(this); })
.mouseover(function () { ac.highlight(this); })
.mouseout(function () { ac.unhighlight(this); })
.data('autocompleteValue', key)
.appendTo(ul);
}
}
// Show popup with matches, if any.
......@@ -271,7 +277,7 @@ Drupal.ACDB.prototype.search = function (searchString) {
// See if this string needs to be searched for anyway.
searchString = searchString.replace(/^\s+|\s+$/, '');
if (searchString.length <= 0 ||
searchString.charAt(searchString.length - 1) == ',') {
searchString.charAt(searchString.length - 1) === ',') {
return;
}
......@@ -293,10 +299,10 @@ Drupal.ACDB.prototype.search = function (searchString) {
url: db.uri + '/' + encodeURIComponent(searchString),
dataType: 'json',
success: function (matches) {
if (typeof matches.status == 'undefined' || matches.status != 0) {
if (typeof matches.status === 'undefined' || matches.status !== 0) {
db.cache[searchString] = matches;
// Verify if these are still the matches the user wants to see.
if (db.searchString == searchString) {
if (db.searchString === searchString) {
db.owner.found(matches);
}
db.owner.setStatus('found');
......@@ -313,8 +319,12 @@ Drupal.ACDB.prototype.search = function (searchString) {
* Cancels the current autocomplete request.
*/
Drupal.ACDB.prototype.cancel = function () {
if (this.owner) this.owner.setStatus('cancel');
if (this.timer) clearTimeout(this.timer);
if (this.owner) {
this.owner.setStatus('cancel');
}
if (this.timer) {
clearTimeout(this.timer);
}
this.searchString = '';
};
......
......@@ -221,7 +221,17 @@ function _book_outline_access($node) {
* @see book_menu()
*/
function _book_outline_remove_access($node) {
return isset($node->book) && ($node->book['bid'] != $node->nid) && _book_outline_access($node);
return _book_node_is_removable($node) && _book_outline_access($node);
}
/**
* Determines if a node can be removed from the book.
*
* A node can be removed from a book if it is actually in a book and it either
* is not a top-level page or is a top-level page with no children.
*/
function _book_node_is_removable($node) {
return (!empty($node->book['bid']) && (($node->book['bid'] != $node->nid) || !$node->book['has_children']));
}
/**
......
......@@ -149,7 +149,7 @@ function book_outline_form($form, &$form_state, $node) {
$form['remove'] = array(
'#type' => 'submit',
'#value' => t('Remove from book outline'),
'#access' => $node->nid != $node->book['bid'] && $node->book['bid'],
'#access' => _book_node_is_removable($node),
'#weight' => 20,
'#submit' => array('book_remove_button_submit'),
);
......@@ -231,8 +231,7 @@ function book_remove_form($form, &$form_state, $node) {
*/
function book_remove_form_submit($form, &$form_state) {
$node = $form['#node'];
if ($node->nid != $node->book['bid']) {
// Only allowed when this is not a book (top-level page).
if (_book_node_is_removable($node)) {
menu_link_delete($node->book['mlid']);
db_delete('book')
->condition('nid', $node->nid)
......
......@@ -32,7 +32,7 @@ class BookTestCase extends DrupalWebTestCase {
// Create users.
$this->book_author = $this->drupalCreateUser(array('create new books', 'create book content', 'edit own book content', 'add content to books'));
$this->web_user = $this->drupalCreateUser(array('access printer-friendly version', 'node test view'));
$this->admin_user = $this->drupalCreateUser(array('create new books', 'create book content', 'edit own book content', 'add content to books', 'administer blocks', 'administer permissions'));
$this->admin_user = $this->drupalCreateUser(array('create new books', 'create book content', 'edit own book content', 'add content to books', 'administer blocks', 'administer permissions', 'administer book outlines', 'node test view'));
}
/**
......@@ -332,4 +332,30 @@ class BookTestCase extends DrupalWebTestCase {
$this->drupalGet('node/' . $this->book->nid);
$this->assertText($block_title, t('Book navigation block is displayed to anonymous users.'));
}
/**
* Tests the access for deleting top-level book nodes.
*/
function testBookDelete() {
$nodes = $this->createBook();
$this->drupalLogin($this->admin_user);
$edit = array();
// Test access to delete top-level and child book nodes.
$this->drupalGet('node/' . $this->book->nid . '/outline/remove');
$this->assertResponse('403', t('Deleting top-level book node properly forbidden.'));
$this->drupalPost('node/' . $nodes[4]->nid . '/outline/remove', $edit, t('Remove'));
$node4 = node_load($nodes[4]->nid, NULL, TRUE);
$this->assertTrue(empty($node4->book), t('Deleting child book node properly allowed.'));
// Delete all child book nodes and retest top-level node deletion.
foreach ($nodes as $node) {
$nids[] = $node->nid;
}
node_delete_multiple($nids);
$this->drupalPost('node/' . $this->book->nid . '/outline/remove', $edit, t('Remove'));
$node = node_load($this->book->nid, NULL, TRUE);
$this->assertTrue(empty($node->book), t('Deleting childless top-level book node properly allowed.'));
}
}
......@@ -1841,7 +1841,7 @@ function comment_form($form, &$form_state, $comment) {
// If a content type has multilingual support we set the comment to inherit the
// content language. Otherwise mark the comment as language neutral.
$comment_langcode = $comment->language;
if (($comment_langcode == LANGUAGE_NONE) && variable_get('language_content_type_' . $node->type, 0)) {
if (($comment_langcode == LANGUAGE_NONE) && variable_get('node_type_language_' . $node->type, 0)) {
$comment_langcode = $language_content->langcode;
}
$form['language'] = array(
......
......@@ -345,7 +345,7 @@ function list_field_update_forbid($field, $prior_field, $has_data) {
// Forbid any update that removes allowed values with actual data.
$lost_keys = array_diff(array_keys($prior_field['settings']['allowed_values']), array_keys($field['settings']['allowed_values']));
if (_list_values_in_use($field, $lost_keys)) {
throw new FieldUpdateForbiddenException(t('Cannot update a list field to not include keys with existing data.'));
throw new FieldUpdateForbiddenException(t('A list field (@field_name) with existing data cannot have its keys changed.', array('@field_name' => $field['field_name'])));
}
}
}
......
......@@ -434,7 +434,7 @@ class TextTranslationTestCase extends DrupalWebTestCase {
$this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
// Set "Article" content type to use multilingual support with translation.
$edit = array('language_content_type' => 2);
$edit = array('node_type_language' => TRANSLATION_ENABLED);
$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.'));
}
......
......@@ -779,7 +779,7 @@ function forum_forum_load($tid = NULL) {
$query->addExpression('SUM(ncs.comment_count)', 'comment_count');
$counts = $query
->fields('f', array('tid'))
->condition('status', 1)
->condition('n.status', 1)
->groupBy('tid')
->addTag('node_access')
->execute()
......
......@@ -6,21 +6,21 @@
*/
/**
* Setting for language negotiation options
* Builds the configuration form for language negotiation.
*/
function locale_languages_configure_form() {
function language_negotiation_configure_form() {
include_once DRUPAL_ROOT . '/core/includes/language.inc';
$form = array(
'#submit' => array('locale_languages_configure_form_submit'),
'#theme' => 'locale_languages_configure_form',
'#submit' => array('language_negotiation_configure_form_submit'),
'#theme' => 'language_negotiation_configure_form',
'#language_types' => language_types_configurable(FALSE),
'#language_types_info' => language_types_info(),
'#language_providers' => language_negotiation_info(),
);
foreach ($form['#language_types'] as $type) {
_locale_languages_configure_form_language_table($form, $type);
language_negotiation_configure_form_table($form, $type);
}
$form['actions'] = array('#type' => 'actions');
......@@ -35,7 +35,7 @@ function locale_languages_configure_form() {
/**
* Helper function to build a language provider table.
*/
function _locale_languages_configure_form_language_table(&$form, $type) {
function language_negotiation_configure_form_table(&$form, $type) {
$info = $form['#language_types_info'][$type];
$table_form = array(
......@@ -117,7 +117,7 @@ function _locale_languages_configure_form_language_table(&$form, $type) {
}
/**
* Returns HTML for a language configuration form.
* Returns HTML for the language negotiation configuration form.
*
* @param $variables
* An associative array containing:
......@@ -125,7 +125,7 @@ function _locale_languages_configure_form_language_table(&$form, $type) {
*
* @ingroup themeable
*/
function theme_locale_languages_configure_form($variables) {
function theme_language_negotiation_configure_form($variables) {
$form = $variables['form'];
$output = '';
......@@ -186,7 +186,7 @@ function theme_locale_languages_configure_form($variables) {
/**
* Submit handler for language negotiation settings.
*/
function locale_languages_configure_form_submit($form, &$form_state) {
function language_negotiation_configure_form_submit($form, &$form_state) {
$configurable_types = $form['#language_types'];
foreach ($configurable_types as $type) {
......@@ -211,14 +211,14 @@ function locale_languages_configure_form_submit($form, &$form_state) {
// configuration.
language_types_set();
$form_state['redirect'] = 'admin/config/regional/language/configure';
$form_state['redirect'] = 'admin/config/regional/language/detection';
drupal_set_message(t('Language negotiation configuration saved.'));
}
/**
* The URL language provider configuration form.
* Builds the URL language provider configuration form.
*/
function locale_language_providers_url_form($form, &$form_state) {
function language_negotiation_configure_url_form($form, &$form_state) {
$form['locale_language_negotiation_url_part'] = array(
'#title' => t('Part of the URL that determines language'),
'#type' => 'radios',
......@@ -276,7 +276,7 @@ function locale_language_providers_url_form($form, &$form_state) {
);
}
$form_state['redirect'] = 'admin/config/regional/language/configure';
$form_state['redirect'] = 'admin/config/regional/language/detection';
$form['actions']['#type'] = 'actions';
$form['actions']['submit'] = array(
......@@ -292,7 +292,7 @@ function locale_language_providers_url_form($form, &$form_state) {
* Validate that the prefixes and domains are unique, and make sure that
* the prefix and domain are only blank for the default.
*/
function locale_language_providers_url_form_validate($form, &$form_state) {
function language_negotiation_configure_url_form_validate($form, &$form_state) {
// Get the enabled languages only.
$languages = language_list(TRUE);
$default = language_default();
......@@ -335,7 +335,7 @@ function locale_language_providers_url_form_validate($form, &$form_state) {
/**
* Save URL negotiation provider settings.
*/
function locale_language_providers_url_form_submit($form, &$form_state) {
function language_negotiation_configure_url_form_submit($form, &$form_state) {
// Save selected format (prefix or domain).
variable_set('locale_language_negotiation_url_part', $form_state['values']['locale_language_negotiation_url_part']);
......@@ -350,7 +350,7 @@ function locale_language_providers_url_form_submit($form, &$form_state) {
/**
* The URL language provider configuration form.
*/
function locale_language_providers_session_form($form, &$form_state) {
function language_negotiation_configure_session_form($form, &$form_state) {
$form['locale_language_negotiation_session_param'] = array(
'#title' => t('Request/session parameter'),
'#type' => 'textfield',
......@@ -358,7 +358,7 @@ function locale_language_providers_session_form($form, &$form_state) {
'#description' => t('Name of the request/session parameter used to determine the desired language.'),
);
$form_state['redirect'] = 'admin/config/regional/language/configure';
$form_state['redirect'] = 'admin/config/regional/language/detection';
return system_settings_form($form);
}
......
......@@ -150,7 +150,7 @@ function hook_language_negotiation_info() {
*/
function hook_language_negotiation_info_alter(array &$language_providers) {
if (isset($language_providers['custom_language_provider'])) {
$language_providers['custom_language_provider']['config'] = 'admin/config/regional/language/configure/custom-language-provider';
$language_providers['custom_language_provider']['config'] = 'admin/config/regional/language/detection/custom-language-provider';
}
}
......
......@@ -40,11 +40,11 @@ function locale_help($path, $arg) {
case 'admin/config/regional/language':
return '<p>' . t('Interface text can be translated. <a href="@translations">Download contributed translations</a> from Drupal.org.', array('@translations' => 'http://localize.drupal.org')) . '</p>';
case 'admin/config/regional/language/configure':
case 'admin/config/regional/language/detection':
$output = '<p>' . t("Define how to decide which language is used to display page elements (primarily text provided by Drupal and modules, such as field labels and help text). This decision is made by evaluating a series of detection methods for languages; the first detection method that gets a result will determine which language is used for that type of text. Define the order of evaluation of language detection methods on this page.") . '</p>';
return $output;
case 'admin/config/regional/language/configure/session':
case 'admin/config/regional/language/detection/session':
$output = '<p>' . t('Determine the language from a request/session parameter. Example: "http://example.com?language=de" sets language to German based on the use of "de" within the "language" parameter.') . '</p>';
return $output;
......@@ -62,7 +62,7 @@ function locale_help($path, $arg) {
case 'admin/structure/block/manage/%/%':
if ($arg[4] == 'locale' && $arg[5] == 'language') {
return '<p>' . t('This block is only shown if <a href="@languages">at least two languages are enabled</a> and <a href="@configuration">language negotiation</a> is set to <em>URL</em> or <em>Session</em>.', array('@languages' => url('admin/config/regional/language'), '@configuration' => url('admin/config/regional/language/configure'))) . '</p>';
return '<p>' . t('This block is only shown if <a href="@languages">at least two languages are enabled</a> and <a href="@configuration">language negotiation</a> is set to <em>URL</em> or <em>Session</em>.', array('@languages' => url('admin/config/regional/language'), '@configuration' => url('admin/config/regional/language/detection'))) . '</p>';
}
break;
}
......@@ -73,27 +73,27 @@ function locale_help($path, $arg) {
*/
function locale_menu() {
// Language negotiation.
$items['admin/config/regional/language/configure'] = array(
$items['admin/config/regional/language/detection'] = array(
'title' => 'Detection and selection',
'page callback' => 'drupal_get_form',
'page arguments' => array('locale_languages_configure_form'),
'page arguments' => array('language_negotiation_configure_form'),
'access arguments' => array('administer languages'),
'weight' => 10,
'file' => 'locale.admin.inc',
'type' => MENU_LOCAL_TASK,
);
$items['admin/config/regional/language/configure/url'] = array(
$items['admin/config/regional/language/detection/url'] = array(
'title' => 'URL language detection configuration',
'page callback' => 'drupal_get_form',
'page arguments' => array('locale_language_providers_url_form'),
'page arguments' => array('language_negotiation_configure_url_form'),
'access arguments' => array('administer languages'),
'file' => 'locale.admin.inc',
'type' => MENU_VISIBLE_IN_BREADCRUMB,
);
$items['admin/config/regional/language/configure/session'] = array(
$items['admin/config/regional/language/detection/session'] = array(
'title' => 'Session language detection configuration',
'page callback' => 'drupal_get_form',
'page arguments' => array('locale_language_providers_session_form'),
'page arguments' => array('language_negotiation_configure_session_form'),
'access arguments' => array('administer languages'),
'file' => 'locale.admin.inc',
'type' => MENU_VISIBLE_IN_BREADCRUMB,
......@@ -246,31 +246,6 @@ function locale_language_selector_form($user) {
return $form;
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function locale_form_node_type_form_alter(&$form, &$form_state) {
if (isset($form['type'])) {
$form['workflow']['language_content_type'] = array(
'#type' => 'radios',
'#title' => t('Multilingual support'),
'#default_value' => variable_get('language_content_type_' . $form['#node_type']->type, 0),
'#options' => array(t('Disabled'), t('Enabled')),
'#description' => t('Enable multilingual support for this content type. If enabled, a language selection field will be added to the editing form, allowing you to select from one of the <a href="!languages">enabled languages</a>. If disabled, new posts are saved with the default language. Existing content will not be affected by changing this option.', array('!languages' => url('admin/config/regional/language'))),
);
}
}
/**
* Return whether the given content type has multilingual support.
*
* @return
* True if multilingual support is enabled.
*/
function locale_multilingual_node_type($type_name) {
return (bool) variable_get('language_content_type_' . $type_name, 0);
}
/**
* Implements hook_form_alter().
*
......@@ -295,28 +270,6 @@ function locale_form_alter(&$form, &$form_state, $form_id) {
* Implements hook_form_BASE_FORM_ID_alter().
*/
function locale_form_node_form_alter(&$form, &$form_state) {
if (isset($form['#node']->type) && locale_multilingual_node_type($form['#node']->type)) {
$languages = language_list(TRUE);
foreach ($languages as $langcode => $language) {
$language_options[$langcode] = $language->name;
}
$form['language'] = array(
'#type' => 'select',
'#title' => t('Language'),
'#default_value' => (isset($form['#node']->language) ? $form['#node']->language : ''),
'#options' => $language_options,
'#empty_value' => LANGUAGE_NONE,
'#empty_option' => t('- None -'),
);
}
// Node type without language selector: assign the default for new nodes
elseif (!isset($form['#node']->nid)) {
$default = language_default();
$form['language'] = array(
'#type' => 'value',
'#value' => $default->langcode
);
}
$form['#submit'][] = 'locale_field_node_form_submit';
}
......@@ -356,7 +309,7 @@ function locale_field_node_form_submit($form, &$form_state) {
*/
function locale_theme() {
return array(
'locale_languages_configure_form' => array(
'language_negotiation_configure_form' => array(
'render element' => 'form',
),
'locale_date_format_form' => array(
......@@ -477,7 +430,7 @@ function locale_language_negotiation_info() {
'weight' => -8,
'name' => t('URL'),
'description' => t('Determine the language from the URL (Path prefix or domain).'),
'config' => 'admin/config/regional/language/configure/url',
'config' => 'admin/config/regional/language/detection/url',
);
$providers[LANGUAGE_NEGOTIATION_SESSION] = array(
......@@ -490,7 +443,7 @@ function locale_language_negotiation_info() {
'weight' => -6,
'name' => t('Session'),
'description' => t('Determine the language from a request/session parameter.'),
'config' => 'admin/config/regional/language/configure/session',
'config' => 'admin/config/regional/language/detection/session',
);
$providers[LANGUAGE_NEGOTIATION_USER] = array(
......@@ -743,29 +696,46 @@ function locale_reset() {
* @param $langcode
* Optional language code to translate to a language other than
* what is used to display the page.
* @return
* The numeric index of the plural variant to use for this $langcode and
* $count combination or -1 if the language was not found or does not have a
* plural formula.
*/
function locale_get_plural($count, $langcode = NULL) {
global $language;
$locale_plurals = &drupal_static(__FUNCTION__, array());
$plurals = &drupal_static(__FUNCTION__ . ':plurals', array());
// Used to locally cache the plural formulas for all languages.
$plural_formulas = &drupal_static(__FUNCTION__, array());
// Used to store precomputed plural indexes corresponding to numbers
// individually for each language.
$plural_indexes = &drupal_static(__FUNCTION__ . ':plurals', array());
$langcode = $langcode ? $langcode : $language->langcode;
if (!isset($plurals[$langcode][$count])) {
if (empty($locale_plural_formulas)) {
$locale_plurals = variable_get('locale_translation_plurals', array());
if (!isset($plural_indexes[$langcode][$count])) {
// Retrieve and statically cache the plural formulas for all languages.
if (empty($plural_formulas)) {
$plural_formulas = variable_get('locale_translation_plurals', array());
}
if (!empty($locale_plurals[$langcode])) {
// If there is a plural formula for the language, evaluate it for the given
// $count and statically cache the result for the combination of language
// and count, since the result will always be identical.
if (!empty($plural_formulas[$langcode])) {
// $n is used inside the expression in the eval().
$n = $count;
$plurals[$langcode][$count] = @eval('return intval(' . $locale_plurals[$langcode]['formula'] . ');');
return $plurals[$langcode][$count];
$plural_indexes[$langcode][$count] = @eval('return intval(' . $plural_formulas[$langcode]['formula'] . ');');
}
// In case there is no plural formula for English (no imported translation
// for English), use a default formula.
elseif ($langcode == 'en') {
$plural_indexes[$langcode][$count] = (int) ($count != 1);
}
// Otherwise, return -1 (unknown).
else {
$plurals[$langcode][$count] = -1;
return -1;
$plural_indexes[$langcode][$count] = -1;
}
}
return $plurals[$langcode][$count];
return $plural_indexes[$langcode][$count];
}
......
This diff is collapsed.
......@@ -187,6 +187,14 @@ function node_type_form($form, &$form_state, $type = NULL) {
),
'#description' => t('Users with the <em>Administer content</em> permission will be able to override these options.'),
);
if (module_exists('language')) {
$form['workflow']['node_type_language'] = array(
'#type' => 'checkbox',
'#title' => t('Multilingual support'),
'#default_value' => variable_get('node_type_language_' . $type->type, 0),
'#description' => t('Add a language selection field to the editing form, allowing you to select from one of the <a href="!languages">enabled languages</a>. If disabled, new posts are saved with the default language. Existing content will not be affected by changing this option.', array('!languages' => url('admin/config/regional/language'))),
);
}
$form['display'] = array(
'#type' => 'fieldset',
'#title' => t('Display settings'),
......
......@@ -456,6 +456,7 @@ function node_uninstall() {
->condition('name', 'node_options_' . $type)
->condition('name', 'node_submitted_' . $type)
->condition('name', 'node_permissions_' . $type)
->condition('name', 'node_type_language_' . $type)
)
->execute();