security updates
have to check views and entityreference for custom patches
This commit is contained in:
@@ -8,9 +8,9 @@ files[] = i18n_object.inc
|
||||
files[] = i18n.test
|
||||
configure = admin/config/regional/i18n
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-08-21
|
||||
version = "7.x-1.10"
|
||||
; Information added by Drupal.org packaging script on 2015-01-26
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1377069696"
|
||||
datestamp = "1422286982"
|
||||
|
||||
|
@@ -22,12 +22,21 @@ function i18n_uninstall() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add fields to schema if they don't exist
|
||||
* Add fields to the schema if they don't exist.
|
||||
*
|
||||
* @param string $table
|
||||
* The name of the database table.
|
||||
* @param array $fields
|
||||
* The list of database fields to create.
|
||||
* @param boolean $force_rebuild_schema
|
||||
* Whether to force drupal_get_schema() to rebuild the schema. This may be
|
||||
* necessary when additional implementations of hook_schema_alter() have
|
||||
* become available since the schema was originally built.
|
||||
*/
|
||||
function i18n_install_create_fields($table, $fields) {
|
||||
function i18n_install_create_fields($table, $fields, $force_rebuild_schema = FALSE) {
|
||||
static $schema;
|
||||
// Do not force schema refresh more than once per request.
|
||||
$schema = drupal_get_schema($table, !isset($schema));
|
||||
$rebuild_schema = !isset($schema) || $force_rebuild_schema;
|
||||
$schema = drupal_get_schema($table, $rebuild_schema);
|
||||
foreach ($fields as $field) {
|
||||
if (!empty($schema['fields'][$field])) {
|
||||
if (!db_field_exists($table, $field)) {
|
||||
|
@@ -403,9 +403,17 @@ function i18n_get_object($type, $key, $object = NULL) {
|
||||
$index = is_array($key) ? implode(':', $key) : $key;
|
||||
if (!isset($cache[$type][$index])) {
|
||||
$class = i18n_object_info($type, 'class', 'i18n_object_wrapper');
|
||||
$cache[$type][$index] = new $class($type, $key, $object);
|
||||
$object_wrapper = new $class($type, $key, $object);
|
||||
// Do not cache object with empty index.
|
||||
if (!empty($index)) {
|
||||
$cache[$type][$index] = $object_wrapper;
|
||||
}
|
||||
}
|
||||
return $cache[$type][$index];
|
||||
else {
|
||||
$object_wrapper = $cache[$type][$index];
|
||||
}
|
||||
|
||||
return $object_wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -498,9 +506,12 @@ function i18n_object_translate_access($type, $object) {
|
||||
*
|
||||
* @param $path
|
||||
* Path to get translations for or '<front>' for front page.
|
||||
* @param $check_access
|
||||
* Whether to check access to paths, defaults to TRUE
|
||||
*/
|
||||
function i18n_get_path_translations($path) {
|
||||
function i18n_get_path_translations($path, $check_access = TRUE) {
|
||||
$translations = &drupal_static(__FUNCTION__);
|
||||
|
||||
if (!isset($translations[$path])) {
|
||||
$translations[$path] = array();
|
||||
foreach (module_implements('i18n_translate_path') as $module) {
|
||||
@@ -510,10 +521,31 @@ function i18n_get_path_translations($path) {
|
||||
$translations[$path] += $translated;
|
||||
}
|
||||
}
|
||||
// Add access information if not there.
|
||||
foreach ($translations[$path] as $langcode => &$info) {
|
||||
if (!isset($info['access'])) {
|
||||
$item = menu_get_item($info['href']);
|
||||
// If no menu item, it may be an external URL, we allow access.
|
||||
$info['access'] = $item ? !empty($item['access']) : TRUE;
|
||||
}
|
||||
}
|
||||
// Chance for altering the results.
|
||||
drupal_alter('i18n_translate_path', $translations[$path], $path);
|
||||
}
|
||||
return $translations[$path];
|
||||
|
||||
if ($check_access) {
|
||||
return array_filter($translations[$path], '_i18n_get_path_translations_access');
|
||||
}
|
||||
else {
|
||||
return $translations[$path];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to check access to path translation.
|
||||
*/
|
||||
function _i18n_get_path_translations_access($path) {
|
||||
return $path['access'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -8,9 +8,9 @@ files[] = i18n_block.inc
|
||||
files[] = i18n_block.test
|
||||
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-08-21
|
||||
version = "7.x-1.10"
|
||||
; Information added by Drupal.org packaging script on 2015-01-26
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1377069696"
|
||||
datestamp = "1422286982"
|
||||
|
||||
|
@@ -59,7 +59,7 @@ function i18n_block_menu_alter(&$items) {
|
||||
*/
|
||||
function i18n_block_translate_tab_access($module, $delta) {
|
||||
$block = block_load($module, $delta);
|
||||
return user_access('translate interface') && isset($block) && ($block->i18n_mode == I18N_MODE_LOCALIZE);
|
||||
return user_access('translate interface') && $block && isset($block->i18n_mode) && ($block->i18n_mode == I18N_MODE_LOCALIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -5,9 +5,9 @@ dependencies[] = i18n_string
|
||||
package = Multilingual - Internationalization
|
||||
core = 7.x
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-08-21
|
||||
version = "7.x-1.10"
|
||||
; Information added by Drupal.org packaging script on 2015-01-26
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1377069696"
|
||||
datestamp = "1422286982"
|
||||
|
||||
|
@@ -72,6 +72,7 @@ function i18n_field_i18n_string_info() {
|
||||
'description' => t('Configurable fields descriptions, defaults, options, etc.'),
|
||||
'format' => FALSE, // This group doesn't have formatted strings
|
||||
'list' => TRUE, // This group can list all strings
|
||||
'class' => 'i18n_string_textgroup_cached',
|
||||
);
|
||||
return $groups;
|
||||
}
|
||||
|
@@ -6,9 +6,9 @@ package = Multilingual - Internationalization
|
||||
core = 7.x
|
||||
files[] = i18n_field.inc
|
||||
files[] = i18n_field.test
|
||||
; Information added by drupal.org packaging script on 2013-08-21
|
||||
version = "7.x-1.10"
|
||||
; Information added by Drupal.org packaging script on 2015-01-26
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1377069696"
|
||||
datestamp = "1422286982"
|
||||
|
||||
|
@@ -248,13 +248,13 @@ function i18n_field_field_widget_form_alter(&$element, &$form_state, $context) {
|
||||
if ($filefield && $single_value && $no_default) {
|
||||
$help_variables = array(
|
||||
'description' => field_filter_xss($instance['description']),
|
||||
'upload_validators' => $alter_element['#upload_validators'],
|
||||
'upload_validators' => isset($alter_element['#upload_validators']) ? $alter_element['#upload_validators'] : array(),
|
||||
);
|
||||
$original_description = theme('file_upload_help', $help_variables);
|
||||
if ($alter_element['#description'] == $original_description) {
|
||||
$help_variables = array(
|
||||
'description' => field_filter_xss($instance_current['description']),
|
||||
'upload_validators' => $alter_element['#upload_validators'],
|
||||
'upload_validators' => isset($alter_element['#upload_validators']) ? $alter_element['#upload_validators'] : array(),
|
||||
);
|
||||
$alter_element['#description'] = theme('file_upload_help', $help_variables);
|
||||
}
|
||||
@@ -403,7 +403,9 @@ function i18n_field_translate_allowed_values($field, $langcode = NULL) {
|
||||
* Translate field default.
|
||||
*/
|
||||
function i18n_field_translate_default($instance, $value, $langcode = NULL) {
|
||||
return i18n_string_translate(array('field', $instance['field_name'], $instance['bundle'], 'default_value'), $value, array('langcode' => $langcode));
|
||||
// The default value does not need sanitizing in a text_textfield widget.
|
||||
$sanitize = !($instance['widget']['type'] == 'text_textfield' && $instance['widget']['module'] == 'text');
|
||||
return i18n_string_translate(array('field', $instance['field_name'], $instance['bundle'], 'default_value'), $value, array('langcode' => $langcode, 'sanitize' => $sanitize));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -7,9 +7,9 @@ package = Multilingual - Internationalization
|
||||
core = 7.x
|
||||
files[] = i18n_forum.test
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-08-21
|
||||
version = "7.x-1.10"
|
||||
; Information added by Drupal.org packaging script on 2015-01-26
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1377069696"
|
||||
datestamp = "1422286982"
|
||||
|
||||
|
@@ -35,7 +35,7 @@ function i18n_forum_menu_local_tasks_alter(&$data, $router_item, $root_path) {
|
||||
if ($vid && ($vocabulary = taxonomy_vocabulary_load($vid)) && ($field = field_info_field('taxonomy_' . $vocabulary->machine_name))) {
|
||||
foreach ($field['bundles']['node'] as $type) {
|
||||
if (isset($data['actions']['output'][$type])) {
|
||||
$data['actions']['output'][$type]['#link']['title'] = t('Add new @node_type', array('@node_type' => i18n_node_type_name($type, node_type_get_name($type))));
|
||||
$data['actions']['output'][$type]['#link']['title'] = t('Add new @node_type', array('@node_type' => i18n_node_type_name($type)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@
|
||||
* Produces a menu translation form.
|
||||
*/
|
||||
function i18n_menu_translation_form($form, $form_state, $translation_set = NULL, $item = NULL) {
|
||||
$translation_set = $translation_set ? $translation_set : i18n_translation_set_create('menu_link');
|
||||
$translation_set = $translation_set ? $translation_set : i18n_translation_set_build('menu_link');
|
||||
$form['translation_set'] = array('#type' => 'value', '#value' => $translation_set);
|
||||
$translations = $translation_set->get_translations();
|
||||
// What to do with title? Let's make it a hidden field for now, some tests relay on it
|
||||
@@ -55,7 +55,7 @@ function i18n_menu_translation_form($form, $form_state, $translation_set = NULL,
|
||||
}
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['update'] = array('#type' => 'submit', '#value' => t('Save'));
|
||||
if ($translation_set) {
|
||||
if (!empty($translation_set->tsid)) {
|
||||
$form['actions']['delete'] = array('#type' => 'submit', '#value' => t('Delete'));
|
||||
}
|
||||
return $form;
|
||||
@@ -244,12 +244,16 @@ function i18n_menu_translation_item_overview($item, $translation_set = NULL) {
|
||||
$title = t('n/a');
|
||||
$options[] = l(t('add translation'), 'admin/structure/menu/manage/' . $item['menu_name'] . '/add', array('query' => array('translation' => $item['mlid'], 'target' => $langcode) + drupal_get_destination()));
|
||||
}
|
||||
$rows[] = array($language_name, $title, implode(" | ", $options));
|
||||
$rows[$langcode] = array(
|
||||
'language' => $language_name,
|
||||
'title' => $title,
|
||||
'operations' => implode(" | ", $options)
|
||||
);
|
||||
}
|
||||
|
||||
drupal_set_title(t('Translations of menu item %title', array('%title' => $item['link_title'])), PASS_THROUGH);
|
||||
|
||||
$build['translation_item_overview'] = array(
|
||||
$build['translation_overview'] = array(
|
||||
'#theme' => 'table',
|
||||
'#header' => $header,
|
||||
'#rows' => $rows,
|
||||
|
@@ -123,8 +123,8 @@ function i18n_menu_item_translation_page($type, $item) {
|
||||
module_load_include('admin.inc', 'i18n_menu');
|
||||
// If the item has a language code, we can only support translation sets.
|
||||
$translation_set = !empty($item['i18n_tsid']) ? i18n_translation_set_load($item['i18n_tsid']) : NULL;
|
||||
$build['overview'] = i18n_menu_translation_item_overview($item, $translation_set);
|
||||
$build['translation_form'] = drupal_get_form('i18n_menu_translation_form', $translation_set, $item);
|
||||
return $build;
|
||||
$overview = i18n_menu_translation_item_overview($item, $translation_set);
|
||||
$translation_form = drupal_get_form('i18n_menu_translation_form', $translation_set, $item);
|
||||
return $overview + $translation_form;
|
||||
}
|
||||
|
||||
|
@@ -10,9 +10,9 @@ core = 7.x
|
||||
files[] = i18n_menu.inc
|
||||
files[] = i18n_menu.test
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-08-21
|
||||
version = "7.x-1.10"
|
||||
; Information added by Drupal.org packaging script on 2015-01-26
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1377069696"
|
||||
datestamp = "1422286982"
|
||||
|
||||
|
@@ -529,6 +529,10 @@ function _i18n_menu_link_process(&$link) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
// Skip if administering this menu item through the node edit form.
|
||||
elseif (arg(0) == 'node' && arg(2) == 'edit' && $link['link_path'] == arg(0) . '/' . arg(1)) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
|
@@ -130,6 +130,8 @@ class i18nMenuTestCase extends Drupali18nTestCase {
|
||||
$this->drupalGet('admin/structure/menu/item/' . $node->menu['mlid'] . '/edit');
|
||||
$this->assertText(t('This menu item belongs to a node, so it will have the same language as the node and cannot be localized.'));
|
||||
$this->assertNoField('language', 'We cannot edit language for menu items that belong to nodes.');
|
||||
// Edit the node and submit it to see if the menu link stays enabled.
|
||||
$this->drupalPost('node/' . $node->nid . '/edit', array(), t('Save'));
|
||||
}
|
||||
// Check menu items show up for the right language.
|
||||
$this->drupalGet('<front>');
|
||||
|
@@ -9,9 +9,9 @@ configure = admin/config/regional/i18n/node
|
||||
files[]=i18n_node.test
|
||||
files[]=i18n_node.variable.inc
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-08-21
|
||||
version = "7.x-1.10"
|
||||
; Information added by Drupal.org packaging script on 2015-01-26
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1377069696"
|
||||
datestamp = "1422286982"
|
||||
|
||||
|
@@ -54,7 +54,7 @@ function i18n_node_block_view_system_help_alter(&$block) {
|
||||
$arg = drupal_help_arg(arg(NULL));
|
||||
if ($arg[0] == 'node' && $arg[1] == 'add' && $arg[2]) {
|
||||
if (($type = node_type_get_type(str_replace('-', '_', $arg[2]))) && !empty($type->help)) {
|
||||
$help = i18n_node_translate_type($type, 'help');
|
||||
$help = i18n_node_translate_type($type, 'help', NULL, array('sanitize' => FALSE));
|
||||
if ($help !== $type->help) {
|
||||
$block['content'] = str_replace(filter_xss_admin($type->help), filter_xss_admin($help), $block['content']);
|
||||
}
|
||||
@@ -64,7 +64,7 @@ function i18n_node_block_view_system_help_alter(&$block) {
|
||||
$node = menu_get_object();
|
||||
if ($node && isset($node->type)) {
|
||||
$type = node_type_get_type($node->type);
|
||||
$help = i18n_node_translate_type($type, 'help');
|
||||
$help = i18n_node_translate_type($type, 'help', NULL, array('sanitize' => FALSE));
|
||||
if ($help !== $type->help) {
|
||||
$block['content'] = str_replace(filter_xss_admin($type->help), filter_xss_admin($help), $block['content']);
|
||||
}
|
||||
@@ -121,6 +121,8 @@ function i18n_node_i18n_translate_path($path) {
|
||||
'href' => 'node/' . $node_translation->nid . $matches[2],
|
||||
'title' => $node_translation->title,
|
||||
'object' => $node_translation,
|
||||
// Performance: for node view add access information right away.
|
||||
'access' => !$matches[2] ? $node_translation->status : NULL,
|
||||
);
|
||||
}
|
||||
return $result;
|
||||
@@ -347,7 +349,7 @@ function i18n_node_textfield_process($element) {
|
||||
static $sent = FALSE;
|
||||
|
||||
// Ensure we send the Javascript only once.
|
||||
if (!$sent && isset($element['#autocomplete_path']) && !empty($element['#autocomplete_path']) && variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE) != LANGUAGE_NEGOTIATION_NONE) {
|
||||
if (!$sent && isset($element['#autocomplete_path']) && !empty($element['#autocomplete_path']) && variable_get('language_negotiation', LANGUAGE_NEGOTIATION_DEFAULT) != LANGUAGE_NEGOTIATION_DEFAULT) {
|
||||
// Add a JS file for node forms.
|
||||
// Determine if we are either editing or translating an existing node.
|
||||
// We can't act on regular node creation because we don't have a specified
|
||||
@@ -442,7 +444,7 @@ function i18n_node_form_node_form_alter(&$form, $form_state) {
|
||||
*
|
||||
* @see http://drupal.org/node/765860
|
||||
*/
|
||||
|
||||
|
||||
// Replace core's node submit callback with our own,
|
||||
// in order to translate the node type name.
|
||||
$key = array_search('node_form_submit', $form['actions']['submit']['#submit']);
|
||||
@@ -464,8 +466,7 @@ function i18n_node_form_submit($form, &$form_state) {
|
||||
$insert = empty($node->nid);
|
||||
node_save($node);
|
||||
$node_link = l(t('view'), 'node/' . $node->nid);
|
||||
$type = node_type_get_type($node->type);
|
||||
$type_name = i18n_node_translate_type($type);
|
||||
$type_name = i18n_node_type_name($node->type);
|
||||
|
||||
$watchdog_args = array('@type' => $node->type, '%title' => $node->title);
|
||||
$t_args = array('@type' => $type_name, '%title' => $node->title);
|
||||
@@ -481,7 +482,7 @@ function i18n_node_form_submit($form, &$form_state) {
|
||||
if ($node->nid) {
|
||||
$form_state['values']['nid'] = $node->nid;
|
||||
$form_state['nid'] = $node->nid;
|
||||
$form_state['redirect'] = 'node/' . $node->nid;
|
||||
$form_state['redirect'] = node_access('view', $node) ? 'node/' . $node->nid : '<front>';
|
||||
}
|
||||
else {
|
||||
// In the unlikely case something went wrong on save, the node will be
|
||||
@@ -516,12 +517,11 @@ function _i18n_node_form_node_form_alter($form, &$form_state) {
|
||||
$form['body_field']['body']['#title'] = i18n_node_translate_type($node->type, 'body', $form['body_field']['body']['#title']);
|
||||
}
|
||||
// Translate page title for node/add/% and node/%/edit pages.
|
||||
$types = node_type_get_types();
|
||||
if (empty($node->nid) && strpos($_GET['q'], 'node/add/' . str_replace('_', '-', $node->type)) === 0) {
|
||||
drupal_set_title(t('Create @name', array('@name' => i18n_node_translate_type($types[$node->type], 'name'))), PASS_THROUGH);
|
||||
drupal_set_title(t('Create @name', array('@name' => i18n_node_type_name($node->type))), PASS_THROUGH);
|
||||
}
|
||||
elseif (!empty($node->nid) && $_GET['q'] == 'node/' . $node->nid . '/edit') {
|
||||
drupal_set_title(t('<em>Edit @type</em> @title', array('@type' => i18n_node_translate_type($types[$node->type], 'name'), '@title' => $node->title)), PASS_THROUGH);
|
||||
drupal_set_title(t('<em>Edit @type</em> @title', array('@type' => i18n_node_type_name($node->type), '@title' => $node->title)), PASS_THROUGH);
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
@@ -553,10 +553,16 @@ function i18n_node_translate_type($type, $property = 'name', $source = NULL, $op
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate node type name (unfiltered)
|
||||
* Get translated node type name (unfiltered)
|
||||
*
|
||||
* @param string $type
|
||||
* Node type.
|
||||
* @param string $name
|
||||
* Optional node type name.
|
||||
*/
|
||||
function i18n_node_type_name($type, $name) {
|
||||
return i18n_string_translate(array('node', 'type', $type, 'name'), $name);
|
||||
function i18n_node_type_name($type, $name = NULL) {
|
||||
$name = isset($name) ? $name : node_type_get_name($type);
|
||||
return i18n_string_translate(array('node', 'type', $type, 'name'), $name, array('sanitize' => FALSE));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -25,7 +25,7 @@ function i18n_node_add_page() {
|
||||
if ($type) {
|
||||
// We just need to translate the description, the title is translated by the menu system
|
||||
// The string will be filtered (xss_admin) on the theme layer
|
||||
$item['description'] = i18n_node_translate_type($type, 'description', $item['description']);
|
||||
$item['description'] = i18n_node_translate_type($type, 'description', $item['description'], array('sanitize' => FALSE));
|
||||
}
|
||||
}
|
||||
return theme('node_add_list', array('content' => $content));
|
||||
|
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Builds placeholder replacement tokens for content types.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_token_info().
|
||||
*/
|
||||
function i18n_node_token_info() {
|
||||
$content_type['i18n-name'] = array(
|
||||
'name' => t("Name (localized)"),
|
||||
'description' => t("The name of the content type."),
|
||||
);
|
||||
$content_type['i18n-description'] = array(
|
||||
'name' => t("Description (localized)"),
|
||||
'description' => t("The optional description of the content type."),
|
||||
);
|
||||
|
||||
return array(
|
||||
'tokens' => array(
|
||||
'content-type' => $content_type,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_tokens().
|
||||
*/
|
||||
function i18n_node_tokens($type, $tokens, array $data = array(), array $options = array()) {
|
||||
$replacements = array();
|
||||
$sanitize = !empty($options['sanitize']) ? TRUE : FALSE;
|
||||
$langcode = isset($options['language']) ? $options['language']->language : i18n_langcode();
|
||||
|
||||
if ($type == 'content-type' && !empty($data['node_type'])) {
|
||||
|
||||
$node_type = $data['node_type'];
|
||||
|
||||
foreach ($tokens as $name => $original) {
|
||||
switch ($name) {
|
||||
|
||||
case 'i18n-name':
|
||||
$name = array('node', 'type', $node_type->type, 'name');
|
||||
$options = array('sanitize' => $sanitize, 'langcode' => $langcode);
|
||||
$name = i18n_string_translate($name, $node_type->name, $options);
|
||||
$replacements[$original] = $name;
|
||||
break;
|
||||
|
||||
case 'i18n-description':
|
||||
$description = array('node', 'type', $node_type->type, 'description');
|
||||
$options = array('sanitize' => $sanitize, 'langcode' => $langcode);
|
||||
$description = i18n_string_translate($description, $node_type->description, $options);
|
||||
$replacements[$original] = $description;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $replacements;
|
||||
}
|
@@ -6,9 +6,9 @@ core = 7.x
|
||||
|
||||
files[] = i18n_path.inc
|
||||
files[] = i18n_path.test
|
||||
; Information added by drupal.org packaging script on 2013-08-21
|
||||
version = "7.x-1.10"
|
||||
; Information added by Drupal.org packaging script on 2015-01-26
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1377069696"
|
||||
datestamp = "1422286982"
|
||||
|
||||
|
@@ -4,9 +4,9 @@ dependencies[] = i18n
|
||||
package = Multilingual - Internationalization
|
||||
core = 7.x
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-08-21
|
||||
version = "7.x-1.10"
|
||||
; Information added by Drupal.org packaging script on 2015-01-26
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1377069696"
|
||||
datestamp = "1422286982"
|
||||
|
||||
|
@@ -6,9 +6,9 @@ core = 7.x
|
||||
configure = admin/config/regional/i18n/select
|
||||
files[] = i18n_select.test
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-08-21
|
||||
version = "7.x-1.10"
|
||||
; Information added by Drupal.org packaging script on 2015-01-26
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1377069696"
|
||||
datestamp = "1422286982"
|
||||
|
||||
|
@@ -149,13 +149,8 @@ function i18n_select_query_node_access_alter(QueryAlterableInterface $query) {
|
||||
* Rewrite taxonomy term queries so language selection options are enforced.
|
||||
*/
|
||||
function i18n_select_query_term_access_alter(QueryAlterableInterface $query) {
|
||||
// dsm($query, 'i18n query alter');
|
||||
|
||||
if (module_exists('i18n_taxonomy')
|
||||
&& i18n_select_mode('taxonomy')
|
||||
&& i18n_select_check_query($query, 'tid')
|
||||
&& ($table_alias = i18n_select_check_table($query, 'taxonomy_term_data', 'tid'))
|
||||
) {
|
||||
if (module_exists('i18n_taxonomy') && i18n_select_mode('taxonomy') && i18n_select_check_query($query, 'tid') &&
|
||||
($table_alias = i18n_select_check_table($query, 'taxonomy_term_data', 'tid'))) {
|
||||
$query->condition($table_alias . '.language', i18n_select_langcodes());
|
||||
// Mark query as altered
|
||||
$query->addTag('i18n_select');
|
||||
@@ -228,7 +223,7 @@ function _i18n_select_table_alias($table) {
|
||||
function i18n_select_check_conditions($query, $table_alias = NULL) {
|
||||
$conditions =& $query->conditions();
|
||||
foreach ($conditions as $index => $condition) {
|
||||
if (is_array($condition) && isset($condition['field'])) {
|
||||
if (is_array($condition) && !empty($condition['field'])) {
|
||||
if (strpos($condition['field'], '.') === FALSE) {
|
||||
if ($table_alias) {
|
||||
// Change the condition to include a table alias.
|
||||
|
@@ -28,7 +28,7 @@ class i18n_string_object {
|
||||
// Properties from metadata
|
||||
public $title;
|
||||
// Array of translations to multiple languages
|
||||
public $translations;
|
||||
public $translations = array();
|
||||
// Textgroup object
|
||||
protected $_textgroup;
|
||||
|
||||
@@ -39,7 +39,49 @@ class i18n_string_object {
|
||||
if ($data) {
|
||||
$this->set_properties($data);
|
||||
}
|
||||
// Attempt to re-build the data from the persistent cache.
|
||||
$this->rebuild_from_cache($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild the object data based on the persistent cache.
|
||||
*
|
||||
* Since the textgroup defines if a string is cacheable or not the caching
|
||||
* of the string objects happens in the textgroup handler itself.
|
||||
*
|
||||
* @see i18n_string_textgroup_cached::__destruct()
|
||||
*/
|
||||
protected function rebuild_from_cache($data = NULL) {
|
||||
// Check if we've the required information to repopulate the cache and do so
|
||||
// if possible.
|
||||
$meta_data_exist = isset($this->textgroup) && isset($this->type) && isset($this->objectid) && isset($this->property);
|
||||
if ($meta_data_exist && ($cache = cache_get($this->get_cid())) && !empty($cache->data)) {
|
||||
// Re-spawn the cached data.
|
||||
// @TODO do we need a array_diff to ensure we don't overwrite the data
|
||||
// provided by the $data parameter?
|
||||
$this->set_properties($cache->data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset cache, needed for tests.
|
||||
*/
|
||||
public function cache_reset() {
|
||||
$this->translations = array();
|
||||
// Ensure a possible persistent cache of this object is cleared too.
|
||||
cache_clear_all($this->get_cid(), 'cache', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the caching id for this object.
|
||||
*
|
||||
* @return string
|
||||
* The caching id.
|
||||
*/
|
||||
public function get_cid() {
|
||||
return 'i18n:string:obj:' . $this->get_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get message parameters from context and string.
|
||||
*/
|
||||
@@ -63,6 +105,10 @@ class i18n_string_object {
|
||||
$this->objectkey = (int)$this->objectid;
|
||||
// Remaining elements glued again with ':'
|
||||
$this->property = $parts ? implode(':', $parts) : '';
|
||||
|
||||
// Attempt to re-build the other data from the persistent cache.
|
||||
$this->rebuild_from_cache();
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
@@ -100,13 +146,14 @@ class i18n_string_object {
|
||||
if (isset($string['format'])) {
|
||||
$this->format = $string['format'];
|
||||
}
|
||||
if (isset($string['title'])) {
|
||||
$this->title = $string['title'];
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->string = $string;
|
||||
}
|
||||
if (isset($string['title'])) {
|
||||
$this->title = $string['title'];
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
@@ -279,9 +326,9 @@ class i18n_string_textgroup_default {
|
||||
// Debug flag, set to true to print out more information.
|
||||
public $debug;
|
||||
// Cached or preloaded string objects
|
||||
public $strings;
|
||||
public $strings = array();
|
||||
// Multiple translations search map
|
||||
protected $cache_multiple;
|
||||
protected $cache_multiple = array();
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
@@ -400,8 +447,13 @@ class i18n_string_textgroup_default {
|
||||
/**
|
||||
* Filter array of strings
|
||||
*
|
||||
* @param $filter
|
||||
* @param array $string_list
|
||||
* Array of strings to be filtered.
|
||||
* @param array $filter
|
||||
* Array of name value conditions.
|
||||
*
|
||||
* @return array
|
||||
* Strings from $string_list that match the filter conditions.
|
||||
*/
|
||||
protected static function string_filter($string_list, $filter) {
|
||||
// Remove 'language' and '*' conditions.
|
||||
@@ -566,7 +618,11 @@ class i18n_string_textgroup_default {
|
||||
public function cache_reset() {
|
||||
$this->strings = array();
|
||||
$this->string_format = array();
|
||||
$this->translations = array();
|
||||
|
||||
// Reset the persistent caches.
|
||||
cache_clear_all('i18n:string:tgroup:' . $this->textgroup , 'cache', TRUE);
|
||||
// Reset the complete string object cache too.
|
||||
cache_clear_all('i18n:string:obj:', 'cache', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -613,7 +669,7 @@ class i18n_string_textgroup_default {
|
||||
public static function load_translation($i18nstring, $langcode) {
|
||||
// Search the database using lid if we've got it or textgroup, context otherwise
|
||||
if (!empty($i18nstring->lid)) {
|
||||
// We've alreay got lid, we just need translation data
|
||||
// We've already got lid, we just need translation data
|
||||
$query = db_select('locales_target', 't');
|
||||
$query->condition('t.lid', $i18nstring->lid);
|
||||
}
|
||||
@@ -1284,3 +1340,163 @@ class i18n_string_object_wrapper extends i18n_object_wrapper {
|
||||
return $this->textgroup()->load_strings(array('type' => $type, 'objectid' => $id));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Textgroup handler for i18n_string API which integrated persistent caching.
|
||||
*/
|
||||
class i18n_string_textgroup_cached extends i18n_string_textgroup_default {
|
||||
|
||||
/**
|
||||
* Defines the timeout for the persistent caching.
|
||||
* @var int
|
||||
*/
|
||||
public $caching_time = CACHE_TEMPORARY;
|
||||
|
||||
/**
|
||||
* Extends the existing constructor with a cache handling.
|
||||
*
|
||||
* @param string $textgroup
|
||||
* The name of this textgroup.
|
||||
*/
|
||||
public function __construct($textgroup) {
|
||||
parent::__construct($textgroup);
|
||||
// Fetch persistent caches, the persistent caches contain only metadata.
|
||||
// Those metadata are processed by the related cache_get() methods.
|
||||
foreach (array('cache_multiple', 'strings') as $caches_type) {
|
||||
if (($cache = cache_get('i18n:string:tgroup:' . $this->textgroup . ':' . $caches_type)) && !empty($cache->data)) {
|
||||
$this->{$caches_type} = $cache->data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class destructor.
|
||||
*
|
||||
* Updates the persistent caches for the next usage.
|
||||
* This function not only stores the data of the textgroup objects but also
|
||||
* of the string objects. That way we ensure that only cacheable string object
|
||||
* go into the persistent cache.
|
||||
*/
|
||||
public function __destruct() {
|
||||
// Reduce size to cache by removing NULL values.
|
||||
$this->strings = array_filter($this->strings);
|
||||
|
||||
|
||||
$strings_to_cache = array();
|
||||
// Store the persistent caches. We just store the metadata the translations
|
||||
// are stored by the string object itself. However storing the metadata
|
||||
// reduces the number of DB queries executed during runtime.
|
||||
$cache_data = array();
|
||||
foreach ($this->strings as $context => $i18n_string_object) {
|
||||
$cache_data[$context] = $context;
|
||||
$strings_to_cache[$context] = $i18n_string_object;
|
||||
}
|
||||
cache_set('i18n:string:tgroup:' . $this->textgroup . ':strings', $cache_data, 'cache', $this->caching_time);
|
||||
|
||||
$cache_data = array();
|
||||
foreach ($this->cache_multiple as $pattern => $strings) {
|
||||
foreach ($strings as $context => $i18n_string_object) {
|
||||
$cache_data[$pattern][$context] = $context;
|
||||
$strings_to_cache[$context] = $i18n_string_object;
|
||||
}
|
||||
}
|
||||
cache_set('i18n:string:tgroup:' . $this->textgroup . ':cache_multiple', $cache_data, 'cache', $this->caching_time);
|
||||
|
||||
// Cache the string objects related to this textgroup.
|
||||
// Store only the public visible data into the persistent cache.
|
||||
foreach ($strings_to_cache as $i18n_string_object) {
|
||||
// If this isn't an object it's an unprocessed cache item and doesn't need
|
||||
// to be stored again.
|
||||
if (is_object($i18n_string_object)) {
|
||||
cache_set($i18n_string_object->get_cid(), get_object_vars($i18n_string_object), 'cache', $this->caching_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset cache, needed for tests.
|
||||
*
|
||||
* Takes care of the persistent caches.
|
||||
*/
|
||||
public function cache_reset() {
|
||||
// Reset the persistent caches.
|
||||
cache_clear_all('i18n:string:tgroup:' . $this->textgroup , 'cache', TRUE);
|
||||
// Reset the complete string object cache too. This will affect string
|
||||
// objects of other textgroups as well.
|
||||
cache_clear_all('i18n:string:obj:', 'cache', TRUE);
|
||||
|
||||
return parent::cache_reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get translation from cache.
|
||||
*
|
||||
* Extends the original handler with persistent caching.
|
||||
*
|
||||
* @param string $context
|
||||
* The context to look out for.
|
||||
* @return i18n_string_object|NULL
|
||||
* The string object if available or NULL otherwise.
|
||||
*/
|
||||
protected function cache_get($context) {
|
||||
if (isset($this->strings[$context])) {
|
||||
// If the cache contains a string re-build i18n_string_object.
|
||||
if (is_string($this->strings[$context])) {
|
||||
$i8n_string_object = new i18n_string_object(array('textgroup' => $this->textgroup));
|
||||
$i8n_string_object->set_context($context);
|
||||
$this->strings[$context] = $i8n_string_object;
|
||||
}
|
||||
// Now run the original handling.
|
||||
return parent::cache_get($context);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get strings from multiple cache.
|
||||
*
|
||||
* @param $context array
|
||||
* String context as array with language property at the end.
|
||||
*
|
||||
* @return mixed
|
||||
* Array of strings (may be empty) if we've got a cache hit.
|
||||
* Null otherwise.
|
||||
*/
|
||||
protected function multiple_cache_get($context) {
|
||||
// Ensure the values from the persistent cache are properly re-build.
|
||||
$cache_key = implode(':', $context);
|
||||
if (isset($this->cache_multiple[$cache_key])) {
|
||||
foreach ($this->cache_multiple[$cache_key] as $cached_context) {
|
||||
if (is_string($cached_context)) {
|
||||
$i8n_string_object = new i18n_string_object(array('textgroup' => $this->textgroup));
|
||||
$i8n_string_object->set_context($cached_context);
|
||||
$this->cache_multiple[$cache_key][$cached_context] = $i8n_string_object;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Now we try more generic keys. For instance, if we are searching 'term:1:*'
|
||||
// we may try too 'term:*:*' and filter out the results.
|
||||
foreach ($context as $key => $value) {
|
||||
if ($value != '*') {
|
||||
$try = array_merge($context, array($key => '*'));
|
||||
return $this->multiple_cache_get($try);
|
||||
}
|
||||
}
|
||||
}
|
||||
return parent::multiple_cache_get($context);
|
||||
}
|
||||
|
||||
public function string_update($i18nstring, $options = array()) {
|
||||
// Flush persistent cache.
|
||||
cache_clear_all($i18nstring->get_cid(), 'cache', TRUE);
|
||||
return parent::string_update($i18nstring, $options);
|
||||
}
|
||||
|
||||
public function string_remove($i18nstring, $options = array()) {
|
||||
// Flush persistent cache.
|
||||
cache_clear_all($i18nstring->get_cid(), 'cache', TRUE);
|
||||
return parent::string_remove($i18nstring, $options);
|
||||
}
|
||||
}
|
||||
|
@@ -10,9 +10,9 @@ files[] = i18n_string.inc
|
||||
files[] = i18n_string.test
|
||||
configure = admin/config/regional/i18n/strings
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-08-21
|
||||
version = "7.x-1.10"
|
||||
; Information added by Drupal.org packaging script on 2015-01-26
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1377069696"
|
||||
datestamp = "1422286982"
|
||||
|
||||
|
@@ -28,6 +28,8 @@ function i18n_string_install() {
|
||||
i18n_string_update_7000();
|
||||
i18n_string_update_7001();
|
||||
}
|
||||
// Create new index in {locales_source}, performance improvement in sites with i18n.
|
||||
db_add_index('locales_source', 'textgroup_context', array('textgroup', 'context'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,6 +38,8 @@ function i18n_string_install() {
|
||||
function i18n_string_uninstall() {
|
||||
// Drop custom field.
|
||||
db_drop_field('locales_target', 'i18n_status');
|
||||
// Drop custom index in locales_source table
|
||||
db_drop_index('locales_source', 'textgroup_context');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,6 +234,14 @@ function i18n_string_update_7001() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new index in {locales_source}, performance improvement in sites with i18n.
|
||||
*/
|
||||
function i18n_string_update_7002() {
|
||||
db_add_index('locales_source', 'textgroup_context', array('textgroup', 'context'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notes for update script
|
||||
*/
|
||||
|
@@ -398,6 +398,9 @@ function i18n_string_locale_translate_edit_form_submit($form, &$form_state) {
|
||||
// Invoke locale submission.
|
||||
locale_translate_edit_form_submit($form, $form_state);
|
||||
$lid = $form_state['values']['lid'];
|
||||
if ($i18n_string_object = i18n_string_get_by_lid($lid)) {
|
||||
$i18n_string_object->cache_reset();
|
||||
}
|
||||
foreach ($form_state['values']['translations'] as $key => $value) {
|
||||
if (!empty($value)) {
|
||||
// An update has been made, so we assume the translation is now current.
|
||||
|
@@ -24,7 +24,7 @@ class i18nStringTestCase extends Drupali18nTestCase {
|
||||
|
||||
function setUp() {
|
||||
// We can use any of the modules that define a text group, to use it for testing
|
||||
parent::setUp('i18n_string', 'i18n_menu');
|
||||
parent::setUp('i18n_string', 'i18n_menu', 'i18n_test');
|
||||
parent::setUpLanguages();
|
||||
$this->translator = $this->drupalCreateUser(array('translate interface', 'translate user-defined strings'));
|
||||
}
|
||||
@@ -55,6 +55,106 @@ class i18nStringTestCase extends Drupali18nTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test base i18n_string caching.
|
||||
*/
|
||||
function testCaching() {
|
||||
// Create a bunch of strings for all languages.
|
||||
$textgroup = 'test_cached';
|
||||
$strings = $this->stringCreateArray(2);
|
||||
$translations = array();
|
||||
$textgroup_object = i18n_string_textgroup($textgroup);
|
||||
// Save source strings and store translations.
|
||||
foreach ($strings as $key => $string) {
|
||||
$name = "$textgroup:item:$key:title";
|
||||
i18n_string_update($name, $string);
|
||||
$translations[$key] = $this->createStringTranslation($textgroup, $string);
|
||||
}
|
||||
|
||||
// Now fetch the strings to fill the cache.
|
||||
foreach ($textgroup_object->strings as $context => $string_object) {
|
||||
$this->drupalGet('tests/i18n/i18n_string_build/' . $textgroup . ':' . $context);
|
||||
}
|
||||
foreach ($strings as $key => $string) {
|
||||
$this->drupalGet('tests/i18n/i18n_string_translation_search/' . $textgroup . ':item:' . $key . ':*/es');
|
||||
}
|
||||
|
||||
// Check the persistent cache for contents.
|
||||
$cache = cache_get('i18n:string:tgroup:' . $textgroup . ':strings');
|
||||
if ($this->assertNotEqual($cache, FALSE, 'Textgroup strings cache found')) {
|
||||
foreach ($textgroup_object->strings as $context => $string_object) {
|
||||
if ($this->assertTrue(isset($cache->data[$context]), format_string('Cached string %context found', array('%context' => $context)))) {
|
||||
$this->assertEqual($cache->data[$context], $context, 'Cached string is a string and not an object');
|
||||
}
|
||||
// Check if the string object cache is also available.
|
||||
$string_cache = cache_get($string_object->get_cid());
|
||||
if ($this->assertNotEqual($string_cache, FALSE, format_string('Cached string object %cid found', array('%cid' => $string_object->get_cid())))) {
|
||||
$this->assertTrue(is_array($string_cache->data), 'Cached string object is an array.');
|
||||
}
|
||||
}
|
||||
}
|
||||
$cache = cache_get('i18n:string:tgroup:' . $textgroup . ':cache_multiple');
|
||||
if ($this->assertNotEqual($cache, FALSE, 'Textgroup cache_multiple cache found')) {
|
||||
foreach ($strings as $key => $string) {
|
||||
$pattern = 'item:' . $key . ':*:es';
|
||||
if ($this->assertTrue(isset($cache->data[$pattern]), format_string('Cached multiple cache for pattern %pattern found', array('%pattern_key' => $pattern)))) {
|
||||
$property_pattern = 'item:' . $key . ':title';
|
||||
if ($this->assertTrue(isset($cache->data[$pattern][$property_pattern]), format_string('Cached multiple property title found', array('%pattern_key' => $pattern)))) {
|
||||
$this->assertEqual($cache->data[$pattern][$property_pattern], $property_pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test cache injection.
|
||||
foreach ($textgroup_object->strings as $context => $string_object) {
|
||||
// Check if the string object cache is also available.
|
||||
$string_cache = cache_get($string_object->get_cid());
|
||||
if (isset($string_cache->data)) {
|
||||
// Modify cache.
|
||||
$string_cache->data['string'] = "Injected value.";
|
||||
cache_set($string_object->get_cid(), $string_cache->data, 'cache', CACHE_TEMPORARY);
|
||||
|
||||
// Check if modification is reflected on the next page call.
|
||||
$this->drupalGet('tests/i18n/i18n_string_build/' . $textgroup . ':' . $context);
|
||||
$this->assertText($string_cache->data['string']);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that un-translated strings are cached correctly.
|
||||
$textgroup = 'test_cached';
|
||||
$key = 3;
|
||||
$string = self::randomName(100);
|
||||
$name = "$textgroup:item:$key:title";
|
||||
i18n_string_update($name, $string);
|
||||
|
||||
// Generate the cache entry.
|
||||
$string_object = i18n_string_build($name, $string);
|
||||
$langcode = i18n_langcode();
|
||||
$string_object->get_translation($langcode);
|
||||
|
||||
// Destroy the textgroup object to write the cache entry.
|
||||
$textgroup_object = i18n_string_textgroup($textgroup);
|
||||
$textgroup_object->__destruct();
|
||||
$this->assertTrue(cache_get($string_object->get_cid()) !== FALSE, "Cache entry created.");
|
||||
drupal_static_reset('i18n_string_textgroup');
|
||||
|
||||
// Reset the loaded translation variable.
|
||||
variable_del('i18n_loaded_translations');
|
||||
$loaded_translations = variable_get('i18n_loaded_translations', array());
|
||||
$this->verbose(var_export($loaded_translations, TRUE));
|
||||
|
||||
// Rebuild the string.
|
||||
$string_object = i18n_string_build($name, $string);
|
||||
$string_object->get_translation($langcode);
|
||||
|
||||
// Check that the string hasn't been loaded.
|
||||
$loaded_translations = variable_get('i18n_loaded_translations', array());
|
||||
$this->verbose(var_export($loaded_translations, TRUE));
|
||||
$this->assertFalse(isset($loaded_translations['test_cached:item:3:title']), "The untranslated string was correctly cached.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create strings for all languages
|
||||
*/
|
||||
@@ -76,7 +176,7 @@ class i18nStringTestCase extends Drupali18nTestCase {
|
||||
/**
|
||||
* Create and store one translation into the db
|
||||
*/
|
||||
public static function stringCreateTranslation($name, $lang, $length = 20) {
|
||||
public function stringCreateTranslation($name, $lang, $length = 20) {
|
||||
$translation = $this->randomName($length);
|
||||
if (self::stringSaveTranslation($name, $lang, $translation)) {
|
||||
return $translation;
|
||||
|
@@ -10,9 +10,9 @@ files[] = i18n_sync.install
|
||||
files[] = i18n_sync.module.inc
|
||||
files[] = i18n_sync.node.inc
|
||||
files[] = i18n_sync.test
|
||||
; Information added by drupal.org packaging script on 2013-08-21
|
||||
version = "7.x-1.10"
|
||||
; Information added by Drupal.org packaging script on 2015-01-26
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1377069696"
|
||||
datestamp = "1422286982"
|
||||
|
||||
|
@@ -11,8 +11,6 @@
|
||||
*
|
||||
* Notes:
|
||||
* This module needs to run after taxonomy, i18n, translation. Check module weight.
|
||||
*
|
||||
* @ TODO Test with CCK when possible, api may have changed.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -71,25 +69,6 @@ function i18n_sync_field_info_alter(&$fields) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter().
|
||||
*/
|
||||
function i18n_sync_form_node_admin_content_alter(&$form, &$form_state) {
|
||||
if (!empty($form['operation']) && $form['operation']['#value'] == 'delete') {
|
||||
$form['#submit'] = array_merge(array('i18n_sync_node_delete_submit'), $form['#submit']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter().
|
||||
*/
|
||||
function i18n_sync_form_node_delete_confirm_alter(&$form, &$form_state) {
|
||||
// Intercept form submission so we can handle uploads, replace callback
|
||||
$form['#submit'] = array_merge(array('i18n_sync_node_delete_submit'), $form['#submit']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter().
|
||||
*/
|
||||
@@ -145,42 +124,6 @@ function i18n_sync_form_node_type_form_alter(&$form, &$form_state) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit callback for
|
||||
* - node delete confirm
|
||||
* - node multiple delete confirm
|
||||
*/
|
||||
function i18n_sync_node_delete_submit($form, $form_state) {
|
||||
if ($form_state['values']['confirm']) {
|
||||
if (!empty($form_state['values']['nid'])) {
|
||||
// Single node
|
||||
i18n_sync_node_delete_prepare($form_state['values']['nid']);
|
||||
}
|
||||
elseif (!empty($form_state['values']['nodes'])) {
|
||||
// Multiple nodes
|
||||
foreach ($form_state['values']['nodes'] as $nid => $value) {
|
||||
i18n_sync_node_delete_prepare($nid);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Then it will go through normal form submission
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare node for deletion, work out synchronization issues
|
||||
*/
|
||||
function i18n_sync_node_delete_prepare($nid) {
|
||||
$node = node_load($nid);
|
||||
// Delete file associations when files are shared with existing translations
|
||||
// so they are not removed by upload module
|
||||
if (!empty($node->tnid) && module_exists('upload')) {
|
||||
$result = db_query('SELECT u.* FROM {upload} u WHERE u.nid = %d AND u.fid IN (SELECT t.fid FROM {upload} t WHERE t.fid = u.fid AND t.nid <> u.nid)', $nid);
|
||||
while ($up = db_fetch_object($result)) {
|
||||
db_query("DELETE FROM {upload} WHERE fid = %d AND vid = %d", $up->fid, $up->vid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this node is to be synced
|
||||
*/
|
||||
|
@@ -39,6 +39,7 @@ function i18n_sync_node_translation($node, $translations, $field_names, $op) {
|
||||
continue;
|
||||
}
|
||||
// Load full node, we need all data here.
|
||||
entity_get_controller('node')->resetCache(array($translation->nid));
|
||||
$translation = node_load($translation->nid);
|
||||
$i18n_options = i18n_sync_node_options($node->type);
|
||||
// Invoke callback for each field, the default is just copy over
|
||||
|
@@ -199,7 +199,14 @@ function i18n_taxonomy_translation_term_overview($term) {
|
||||
$path = 'taxonomy/term/' . $translation_term->tid;
|
||||
$title = l($translation_term->name, $path);
|
||||
|
||||
$options[] = l(t('edit'), $path . '/edit');
|
||||
$options['edit'] = array(
|
||||
'#type' => 'link',
|
||||
'#title' => t('edit'),
|
||||
'#href' => $path . '/edit',
|
||||
'#options' => array(
|
||||
'query' => drupal_get_destination(),
|
||||
),
|
||||
);
|
||||
|
||||
if ($translation_term->tid == $i18n_tsid) {
|
||||
$language_name = t('<strong>@language_name</strong> (source)', array('@language_name' => $language_name));
|
||||
@@ -208,14 +215,25 @@ function i18n_taxonomy_translation_term_overview($term) {
|
||||
else {
|
||||
// No such translation in the set yet: help user to create it.
|
||||
$title = t('n/a');
|
||||
$options[] = l(t('add translation'), 'admin/structure/taxonomy/' . $term->vocabulary_machine_name . '/add', array('query' => array('translation' => $term->tid, 'target' => $langcode) + drupal_get_destination()));
|
||||
$options['add'] = array(
|
||||
'#type' => 'link',
|
||||
'#title' => t('add translation'),
|
||||
'#href' => 'admin/structure/taxonomy/' . $term->vocabulary_machine_name . '/add',
|
||||
'#options' => array(
|
||||
'query' => array('translation' => $term->tid, 'target' => $langcode) + drupal_get_destination()
|
||||
),
|
||||
);
|
||||
}
|
||||
$rows[] = array($language_name, $title, implode(" | ", $options));
|
||||
$rows[$langcode] = array(
|
||||
'language' => $language_name,
|
||||
'title' => $title,
|
||||
'operations' => array('data' => $options),
|
||||
);
|
||||
}
|
||||
|
||||
drupal_set_title(t('Translations of term %title', array('%title' => $term->name)), PASS_THROUGH);
|
||||
|
||||
$build['translation_node_overview'] = array(
|
||||
$build['translation_overview'] = array(
|
||||
'#theme' => 'table',
|
||||
'#header' => $header,
|
||||
'#rows' => $rows,
|
||||
|
@@ -11,9 +11,9 @@ files[] = i18n_taxonomy.pages.inc
|
||||
files[] = i18n_taxonomy.admin.inc
|
||||
files[] = i18n_taxonomy.test
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-08-21
|
||||
version = "7.x-1.10"
|
||||
; Information added by Drupal.org packaging script on 2015-01-26
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1377069696"
|
||||
datestamp = "1422286982"
|
||||
|
||||
|
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
function i18n_taxonomy_install() {
|
||||
module_load_install('i18n');
|
||||
i18n_install_create_fields('taxonomy_vocabulary', array('language', 'i18n_mode'));
|
||||
i18n_install_create_fields('taxonomy_vocabulary', array('language', 'i18n_mode'), TRUE);
|
||||
i18n_install_create_fields('taxonomy_term_data', array('language', 'i18n_tsid'));
|
||||
// Set module weight for it to run after core modules, but before views.
|
||||
db_query("UPDATE {system} SET weight = 5 WHERE name = 'i18n_taxonomy' AND type = 'module'");
|
||||
|
@@ -452,17 +452,6 @@ function i18n_taxonomy_translate_path($path, $path_prefix = 'taxonomy/term/') {
|
||||
return $links;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*/
|
||||
function i18n_taxonomy_theme() {
|
||||
return array(
|
||||
'i18n_taxonomy_term_page' => array(
|
||||
'arguments' => array('tids' => array(), 'result' => NULL),
|
||||
'file' => 'i18n_taxonomy.pages.inc',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get localized term name unfiltered.
|
||||
@@ -1231,6 +1220,9 @@ function i18n_taxonomy_entity_info_alter(&$entity_info) {
|
||||
// Core doesn't provide a label callback for taxonomy terms. By setting one
|
||||
// we can use it to return the correct localized term name.
|
||||
$entity_info['taxonomy_term']['label callback'] = 'i18n_taxonomy_taxonomy_term_label';
|
||||
|
||||
// Also let core know terms have languages, now.
|
||||
$entity_info['taxonomy_term']['entity keys']['language'] = 'language';
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -62,37 +62,6 @@ function i18n_taxonomy_term_page($term) {
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a taxonomy term page HTML output.
|
||||
*
|
||||
* @param $tids
|
||||
* An array of term ids.
|
||||
* @param $result
|
||||
* A pager_query() result, such as that performed by taxonomy_select_nodes().
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_i18n_taxonomy_term_page($tids, $result) {
|
||||
drupal_add_css(drupal_get_path('module', 'taxonomy') . '/taxonomy.css');
|
||||
|
||||
$output = '';
|
||||
|
||||
// Only display the description if we have a single term, to avoid clutter and confusion.
|
||||
if (count($tids) == 1) {
|
||||
$term = i18n_taxonomy_localize_terms(taxonomy_term_load($tids[0]));
|
||||
// Check that a description is set.
|
||||
if (!empty($term->description)) {
|
||||
$output .= '<div class="taxonomy-term-description">';
|
||||
$output .= filter_xss_admin($term->description);
|
||||
$output .= '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
$output .= taxonomy_render_nodes($result);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for autocompletion. Replacement for taxonomy_autocomplete
|
||||
*/
|
||||
|
@@ -6,9 +6,9 @@ core = 7.x
|
||||
|
||||
files[] = i18n_translation.inc
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-08-21
|
||||
version = "7.x-1.10"
|
||||
; Information added by Drupal.org packaging script on 2015-01-26
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1377069696"
|
||||
datestamp = "1422286982"
|
||||
|
||||
|
@@ -4,9 +4,9 @@ core = 7.x
|
||||
package = Multilingual - Internationalization
|
||||
dependencies[] = i18n_variable
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-08-21
|
||||
version = "7.x-1.10"
|
||||
; Information added by Drupal.org packaging script on 2015-01-26
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1377069696"
|
||||
datestamp = "1422286982"
|
||||
|
||||
|
@@ -10,9 +10,9 @@ configure = admin/config/regional/i18n/variable
|
||||
files[] = i18n_variable.class.inc
|
||||
files[] = i18n_variable.test
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-08-21
|
||||
version = "7.x-1.10"
|
||||
; Information added by Drupal.org packaging script on 2015-01-26
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1377069696"
|
||||
datestamp = "1422286982"
|
||||
|
||||
|
@@ -7,9 +7,9 @@ package = Testing
|
||||
core = 6.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-08-21
|
||||
version = "7.x-1.10"
|
||||
; Information added by Drupal.org packaging script on 2015-01-26
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1377069696"
|
||||
datestamp = "1422286982"
|
||||
|
||||
|
@@ -36,6 +36,12 @@ function i18n_test_i18n_string_info() {
|
||||
'format' => FALSE, // This group doesn't have strings with format
|
||||
'refresh callback' => 'i18n_test_i18n_string_refresh',
|
||||
);
|
||||
$groups['test_cached'] = array(
|
||||
'title' => t('Test Cached Strings'),
|
||||
'description' => t('Translatable items of a textgroup with caching enabled.'),
|
||||
'format' => FALSE, // This group doesn't have strings with format
|
||||
'class' => 'i18n_string_textgroup_cached_logged',
|
||||
);
|
||||
return $groups;
|
||||
}
|
||||
/**
|
||||
@@ -43,4 +49,53 @@ function i18n_test_i18n_string_info() {
|
||||
*/
|
||||
function i18n_test_i18n_string_refresh() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function i18n_test_menu() {
|
||||
// Required for the i18n_string caching tests.
|
||||
$items['tests/i18n/i18n_string_build/%'] = array(
|
||||
'title' => 'Load string',
|
||||
'access callback' => TRUE,
|
||||
'page callback' => 'i18n_string_build',
|
||||
'page arguments' => array(3),
|
||||
'type' => MENU_CALLBACK,
|
||||
'delivery callback' => 'drupal_json_output',
|
||||
);
|
||||
$items['tests/i18n/i18n_string_build/%/%'] = array(
|
||||
'title' => 'Load string',
|
||||
'access callback' => TRUE,
|
||||
'page callback' => 'i18n_string_build',
|
||||
'page arguments' => array(3, 4),
|
||||
'type' => MENU_CALLBACK,
|
||||
'delivery callback' => 'drupal_json_output',
|
||||
);
|
||||
$items['tests/i18n/i18n_string_translation_search/%'] = array(
|
||||
'title' => 'Search string translations',
|
||||
'access callback' => TRUE,
|
||||
'page callback' => 'i18n_string_translation_search',
|
||||
'page arguments' => array(3),
|
||||
'type' => MENU_CALLBACK,
|
||||
'delivery callback' => 'drupal_json_output',
|
||||
);
|
||||
$items['tests/i18n/i18n_string_translation_search/%/%'] = array(
|
||||
'title' => 'Search string translations',
|
||||
'access callback' => TRUE,
|
||||
'page callback' => 'i18n_string_translation_search',
|
||||
'page arguments' => array(3, 4),
|
||||
'type' => MENU_CALLBACK,
|
||||
'delivery callback' => 'drupal_json_output',
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
class i18n_string_textgroup_cached_logged extends i18n_string_textgroup_cached {
|
||||
public static function load_translation($i18nstring, $langcode) {
|
||||
$strings = variable_get('i18n_loaded_translations', array());
|
||||
$strings[$i18nstring->get_name()] = true;
|
||||
variable_set('i18n_loaded_translations', $strings);
|
||||
parent::load_translation($i18nstring, $langcode);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user