first import

This commit is contained in:
Bachir Soussi Chiadmi
2015-04-08 11:40:19 +02:00
commit 1bc61b12ad
8435 changed files with 1582817 additions and 0 deletions

View File

@@ -0,0 +1,225 @@
<?php
/**
* @file
* Helper functions for taxonomy administration.
*/
/**
* This is the callback for taxonomy translations.
*
* Gets the urls:
* admin/content/taxonomy/%taxonomy_vocabulary/translation
* admin/content/taxonomy/i18n/term/xx
* admin/content/taxonomy/i18n/term/new/xx
* admin/content/taxonomy/vid/translation/op/trid
*/
function i18n_taxonomy_page_vocabulary($vocabulary, $op = NULL, $tid = NULL) {
switch ($op) {
case 'edit':
drupal_set_title(t('Edit term translations'));
$output = drupal_get_form('i18n_taxonomy_translation_term_form', $vocabulary, $tid);
break;
default:
$output = i18n_taxonomy_translation_overview($vocabulary);
}
return $output;
}
/**
* Produces a vocabulary translation form.
*/
function i18n_taxonomy_translation_term_form($form, $form_state, $vocabulary, $translation_set = NULL, $source = NULL) {
$form['translation_set'] = array('#type' => 'value', '#value' => $translation_set);
$translations = $translation_set ? $translation_set->get_translations() : array();
$form['vocabulary'] = array('#type' => 'value', '#value' => $vocabulary);
$form['translations'] = array(
'#type' => 'fieldset',
'#title' => t('Select translations'),
'#description' => t('Select existing terms or type new ones that will be created for each language.'),
'#tree' => TRUE
);
// List of terms for languages.
foreach (i18n_language_list() as $lang => $langname) {
if ($source && $source->language == $lang) {
// This is the source term, we don't change it
$form['source_term'] = array('#type' => 'value', '#value' => $source);
$form['translations'][$lang] = array(
'#title' => $langname,
'#type' => 'item',
'#markup' => $source->name,
'#langcode' => $lang,
);
}
else {
$form['translations'][$lang] = array(
'#title' => $langname,
'#type' => 'textfield',
'#default_value' => isset($translations[$lang]) ? $translations[$lang]->name : '',
'#autocomplete_path' => 'i18n/taxonomy/autocomplete/vocabulary/' . $vocabulary->machine_name . '/' . $lang,
'#langcode' => $lang,
'#maxlength' => 1024,
'#element_validate' => array('i18n_taxonomy_autocomplete_validate'),
);
}
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save')
);
if ($translation_set) {
$form['delete'] = array(
'#type' => 'submit',
'#value' => t('Delete')
);
}
return $form;
}
/**
* Form element validate handler for taxonomy term autocomplete element.
*/
function i18n_taxonomy_autocomplete_validate($element, &$form_state) {
// Autocomplete widgets do not send their tids in the form, so we must detect
// them here and process them independently.
$value = array();
if ($tags = $element['#value']) {
// Collect candidate vocabularies.
$vocabulary = $form_state['values']['vocabulary'];
$vocabularies[$vocabulary->vid] = $vocabulary;
// Translate term names into actual terms.
$typed_terms = drupal_explode_tags($tags);
foreach ($typed_terms as $typed_term) {
// See if the term exists in the chosen vocabulary and return the tid;
// otherwise, create a new 'autocreate' term for insert/update.
if ($possibilities = taxonomy_term_load_multiple(array(), array('name' => trim($typed_term), 'vid' => $vocabulary->vid, 'language' => $element['#langcode']))) {
$term = array_pop($possibilities);
}
else {
$vocabulary = reset($vocabularies);
$term = array(
'tid' => 'autocreate',
'vid' => $vocabulary->vid,
'name' => $typed_term,
'vocabulary_machine_name' => $vocabulary->machine_name,
'language' => $element['#langcode'],
);
}
$value[] = (array)$term;
}
}
form_set_value($element, $value, $form_state);
}
/**
* Form callback: Process vocabulary translation form.
*/
function i18n_taxonomy_translation_term_form_submit($form, &$form_state) {
$translation_set = $form_state['values']['translation_set'];
$vocabulary = $form_state['values']['vocabulary'];
switch ($form_state['values']['op']) {
case t('Save'):
$term_translations = array_filter($form_state['values']['translations']);
foreach ($term_translations as $lang => $lang_terms) {
$item = reset($lang_terms);
if ($item['tid'] == 'autocreate') {
$term = (object) $item;
unset($term->tid);
taxonomy_term_save($term);
}
else {
$term = (object) $item;
}
$translations[$lang] = $term;
}
if (!empty($form_state['values']['source_term'])) {
$term = $form_state['values']['source_term'];
$translations[$term->language] = $term;
}
if (!empty($translations)) {
$translation_set = $translation_set ? $translation_set : i18n_translation_set_create('taxonomy_term', $vocabulary->machine_name);
$translation_set
->reset_translations($translations)
->save(TRUE);
drupal_set_message(t('Term translations have been updated.'));
}
else {
drupal_set_message(t('There are no translations to be saved.'), 'error');
}
break;
case t('Delete'):
$translation_set->delete(TRUE);
drupal_set_message(t('The term translation has been deleted.'));
$form_state['redirect'] = 'admin/structure/taxonomy/' . $form_state['values']['vocabulary']->machine_name . '/translation';
break;
}
}
/**
* Generate a tabular listing of translations for vocabularies.
*/
function i18n_taxonomy_translation_sets_overview($vocabulary) {
module_load_include('admin.inc', 'i18n_translation');
drupal_set_title($vocabulary->name);
$query = db_select('i18n_translation_set', 't')
->condition('t.bundle', $vocabulary->machine_name);
return i18n_translation_admin_overview('taxonomy_term', $query);
}
/**
* Callback for term translation tab.
*/
function i18n_taxonomy_translation_term_overview($term) {
if ($term->i18n_tsid) {
// Already part of a set, grab that set.
$i18n_tsid = $term->i18n_tsid;
$translation_set = i18n_translation_set_load($term->i18n_tsid);
$translation_set->get_translations();
$translations = $translation_set->get_translations();
}
else {
// We have no translation source nid, this could be a new set, emulate that.
$i18n_tsid = $term->tid;
$translations = array($term->language => $term);
}
$type = variable_get('translation_language_type', LANGUAGE_TYPE_INTERFACE);
$header = array(t('Language'), t('Title'), t('Operations'));
foreach (i18n_language_list() as $langcode => $language_name) {
$options = array();
if (isset($translations[$langcode])) {
// Existing translation in the translation set: display status.
// We load the full node to check whether the user can edit it.
$translation_term = taxonomy_term_load($translations[$langcode]->tid);
$path = 'taxonomy/term/' . $translation_term->tid;
$title = l($translation_term->name, $path);
$options[] = l(t('edit'), $path . '/edit');
if ($translation_term->tid == $i18n_tsid) {
$language_name = t('<strong>@language_name</strong> (source)', array('@language_name' => $language_name));
}
}
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()));
}
$rows[] = array($language_name, $title, implode(" | ", $options));
}
drupal_set_title(t('Translations of term %title', array('%title' => $term->name)), PASS_THROUGH);
$build['translation_node_overview'] = array(
'#theme' => 'table',
'#header' => $header,
'#rows' => $rows,
);
return $build;
}

View File

@@ -0,0 +1,136 @@
<?php
/**
* @file
* Internationalization (i18n) hooks
*/
/**
* Implements hook_i18n_object_info().
*/
function i18n_taxonomy_i18n_object_info() {
$info['taxonomy_term'] = array(
'title' => t('Taxonomy term'),
'class' => 'i18n_taxonomy_term',
'entity' => 'taxonomy_term',
'key' => 'tid',
'placeholders' => array(
'%taxonomy_term' => 'tid',
),
// Auto generate edit path
'edit path' => 'taxonomy/term/%taxonomy_term/edit',
// Auto-generate translate tab
'translate tab' => 'taxonomy/term/%taxonomy_term/translate',
'translation set' => TRUE,
'string translation' => array(
'textgroup' => 'taxonomy',
'type' => 'term',
'properties' => array(
'name' => t('Name'),
'description' => array(
'title' => t('Description'),
'format' => 'format',
),
),
)
);
$info['taxonomy_vocabulary'] = array(
'title' => t('Vocabulary'),
'entity' => 'taxonomy_vocabulary',
'key' => 'vid',
'placeholders' => array(
'%taxonomy_vocabulary_machine_name' => 'machine_name',
),
// Auto generate edit path
'edit path' => 'admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/edit',
// Auto-generate translate tab
'translate tab' => 'admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/translate',
// We can easily list all these objects
'list callback' => 'taxonomy_get_vocabularies',
// Metadata for string translation
'string translation' => array(
'textgroup' => 'taxonomy',
'type' => 'vocabulary',
'properties' => array(
'name' => t('Name'),
'description' => t('Description'),
),
),
'translation container' => array(
'name' => t('vocabulary'),
'item type' => 'taxonomy_term',
'item name' => t('terms'),
'options' => array(I18N_MODE_NONE, I18N_MODE_LOCALIZE, I18N_MODE_TRANSLATE, I18N_MODE_LANGUAGE),
),
);
return $info;
}
/**
* Implements hook_i18n_translation_set_info()
*/
function i18n_taxonomy_i18n_translation_set_info() {
$info['taxonomy_term'] = array(
'title' => t('Taxonomy term'),
'class' => 'i18n_taxonomy_translation_set',
'table' => 'taxonomy_term_data',
'field' => 'i18n_tsid',
'parent' => 'taxonomy_vocabulary',
'placeholder' => '%i18n_taxonomy_translation_set',
'list path' => 'admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/list/sets',
'edit path' => 'admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/list/sets/edit/%i18n_taxonomy_translation_set',
'delete path' => 'admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/list/sets/delete/%i18n_taxonomy_translation_set',
'page callback' => 'i18n_taxonomy_term_translation_page',
);
return $info;
}
/**
* Implements hook_i18n_string_info()
*/
function i18n_taxonomy_i18n_string_info() {
$groups['taxonomy'] = array(
'title' => t('Taxonomy'),
'description' => t('Vocabulary titles and term names for localizable vocabularies.'),
'format' => FALSE, // This group doesn't have strings with format
'list' => FALSE, // This group cannot list all strings
'refresh callback' => 'i18n_taxonomy_i18n_string_refresh',
);
return $groups;
}
/**
* Implements hook_i18n_string_objects()
*/
function i18n_taxonomy_i18n_string_objects($type) {
if ($type == 'taxonomy_term') {
$terms = array();
foreach (taxonomy_get_vocabularies() as $vid => $vocabulary) {
if (isset($vocabulary->i18n_mode) && $vocabulary->i18n_mode & I18N_MODE_LOCALIZE) {
foreach (taxonomy_get_tree($vid, 0) as $term) {
$terms[] = $term;
}
}
}
return $terms;
}
}
/**
* Callback for term translation tab.
*
* @param $type
* Should be always 'taxonomy_term'
* @pram $term
* Taxonomy term object
*/
function i18n_taxonomy_term_translation_page($type, $term) {
module_load_include('admin.inc', 'i18n_taxonomy');
$vocabulary = taxonomy_vocabulary_load($term->vid);
$translation_set = !empty($term->i18n_tsid) ? i18n_translation_set_load($term->i18n_tsid) : NULL;
$translation_overview = i18n_taxonomy_translation_term_overview($term);
$translation_term_form = drupal_get_form('i18n_taxonomy_translation_term_form', $vocabulary, $translation_set, $term);
return $translation_overview + $translation_term_form;
}

View File

@@ -0,0 +1,52 @@
<?php
/**
* @file
* Internationalization (i18n) module - Translation set
*/
/**
* @file
* Internationalization (i18n) module - Translation set
*/
class i18n_taxonomy_translation_set extends i18n_translation_set {
/**
* Load all term translations
*/
public function load_translations() {
return i18n_translation_set_index(taxonomy_term_load_multiple(array(), array('i18n_tsid' => $this->tsid)));
}
/**
* Get placeholder values for path replacement
*/
function get_path_placeholders($op = 'list') {
$values = parent::get_path_placeholders($op);
if (!empty($this->bundle)) {
$values['%taxonomy_vocabulary_machine_name'] = $this->bundle;
}
return $values;
}
}
/**
* Taxonomy textgroup handler
*/
class i18n_taxonomy_term extends i18n_string_object_wrapper {
/**
* Translation mode for object
*/
public function get_translate_mode() {
$mode = i18n_taxonomy_vocabulary_mode($this->object->vid);
if ($this->get_langcode()) {
return $mode & I18N_MODE_TRANSLATE;
}
else {
return $mode & I18N_MODE_LOCALIZE;
}
}
/**
* Access to object translation. This should check object properties and permissions
*/
protected function translate_access() {
return taxonomy_term_edit_access($this->object) && $this->get_langcode() && user_access('translate interface');
}
}

View File

@@ -0,0 +1,19 @@
name = Taxonomy translation
description = Enables multilingual taxonomy.
dependencies[] = taxonomy
dependencies[] = i18n_string
dependencies[] = i18n_translation
package = Multilingual - Internationalization
core = 7.x
files[] = i18n_taxonomy.inc
files[] = i18n_taxonomy.pages.inc
files[] = i18n_taxonomy.admin.inc
files[] = i18n_taxonomy.test
; Information added by drupal.org packaging script on 2013-01-13
version = "7.x-1.8"
core = "7.x"
project = "i18n"
datestamp = "1358075001"

View File

@@ -0,0 +1,130 @@
<?php
/**
* @file
* Installation file for i18n_taxonomy module.
*/
/**
* Set language field in its own table.
* Do not drop node.language now, just in case.
* TO-DO: Drop old tables, fields
*/
function i18n_taxonomy_install() {
module_load_install('i18n');
i18n_install_create_fields('taxonomy_vocabulary', array('language', 'i18n_mode'));
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'");
// Set vocabulary mode if updating from D6, module changed name
if (variable_get('i18n_drupal6_update')) {
i18n_taxonomy_update_7000();
}
}
/**
* Implements hook_uninstall().
*/
function i18n_taxonomy_uninstall() {
db_drop_field('taxonomy_vocabulary', 'language');
db_drop_field('taxonomy_vocabulary', 'i18n_mode');
db_drop_field('taxonomy_term_data', 'language');
db_drop_field('taxonomy_term_data', 'i18n_tsid');
variable_del('i18n_taxonomy_vocabulary');
}
/**
* Implements hook_schema_alter().
*/
function i18n_taxonomy_schema_alter(&$schema) {
$schema['taxonomy_vocabulary']['fields']['language'] = array('type' => 'varchar', 'length' => 12, 'not null' => TRUE, 'default' => LANGUAGE_NONE);
$schema['taxonomy_vocabulary']['fields']['i18n_mode'] = array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0);
$schema['taxonomy_term_data']['fields']['language'] = array('type' => 'varchar', 'length' => 12, 'not null' => TRUE, 'default' => LANGUAGE_NONE);
$schema['taxonomy_term_data']['fields']['i18n_tsid'] = array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0);
}
/**
* Implements hook_disable()
*/
function i18n_taxonomy_disable() {
foreach (field_info_fields() as $fieldname => $field) {
if ($field['type'] == 'taxonomy_term_reference' && $field['settings']['options_list_callback'] == 'i18n_taxonomy_allowed_values') {
$field['settings']['options_list_callback'] = NULL;
field_update_field($field);
}
}
}
/**
* Set vocabulary modes from D6 variable
*/
function i18n_taxonomy_update_7000() {
if ($options = variable_get('i18ntaxonomy_vocabulary')) {
foreach ($options as $vid => $mode) {
$mode = $mode == 3 ? I18N_MODE_TRANSLATE : $mode;
db_update('taxonomy_vocabulary')
->fields(array('i18n_mode' => $mode))
->condition('vid', $vid)
->execute();
}
variable_del('i18ntaxonomy_vocabulary');
}
// Move to new translation set system
if (db_field_exists('taxonomy_term_data', 'trid')) {
$query = db_select('taxonomy_term_data', 't');
$query->join('taxonomy_vocabulary', 'v', 't.vid = v.vid');
$query
->fields('t', array('trid'))
->fields('v', array('machine_name'))
->condition('t.trid', 0, '>')
->distinct();
foreach ($query->execute() as $record) {
$tset = i18n_translation_set_create('taxonomy_term', $record->machine_name);
db_update('taxonomy_term_data')
->fields(array('trid' => 0, 'i18n_tsid' => $tset->tsid))
->condition('trid', $record->trid)
->execute();
}
db_drop_field('taxonomy_term_data', 'trid');
}
}
/**
* Drop trid column used in D6 if exists
*/
function i18n_taxonomy_update_7001() {
if (db_field_exists('taxonomy_term_data', 'trid')) {
db_drop_field('taxonomy_term_data', 'trid');
}
}
/**
* Switch back to real taxonomy fields and override option_list_callback.
*/
function i18n_taxonomy_update_7002(&$sandbox) {
foreach (field_info_fields() as $fieldname => $field) {
if ($field['type'] == 'taxonomy_term_reference') {
$field['module'] = 'taxonomy';
$field['settings']['options_list_callback'] = module_exists('i18n_taxonomy') ? 'i18n_taxonomy_allowed_values' : NULL;
drupal_write_record('field_config', $field, array('id'));
}
}
}
/**
* Unset option_list_callback if i18n_taxonomy is disabled.
*/
function i18n_taxonomy_update_7003(&$sandbox) {
if (!function_exists('i18n_taxonomy_allowed_values')) {
i18n_taxonomy_disable();
}
}
/**
* Update D6 language fields in {taxonomy_vocabulary} and {taxonomy_term_data}.
*/
function i18n_taxonomy_update_7004() {
i18n_install_create_fields('taxonomy_vocabulary', array('language'));
i18n_install_create_fields('taxonomy_term_data', array('language'));
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,169 @@
<?php
/**
* @file
* Page callbacks for the taxonomy module, i18n remake.
*/
/**
* Menu callback; displays all nodes associated with a term.
*
* @param $term
* The taxonomy term.
* @return
* The page content.
*/
function i18n_taxonomy_term_page($term) {
$term = i18n_taxonomy_localize_terms($term);
// Assign the term name as the page title.
drupal_set_title($term->name);
// Build breadcrumb based on the hierarchy of the term.
$current = (object) array(
'tid' => $term->tid,
);
// @todo This overrides any other possible breadcrumb and is a pure hard-coded
// presumption. Make this behavior configurable per vocabulary or term.
$breadcrumb = array();
while ($parents = taxonomy_get_parents($current->tid)) {
$parents = i18n_taxonomy_localize_terms($parents);
$current = array_shift($parents);
$breadcrumb[] = l($current->name, 'taxonomy/term/' . $current->tid);
}
$breadcrumb[] = l(t('Home'), NULL);
$breadcrumb = array_reverse($breadcrumb);
drupal_set_breadcrumb($breadcrumb);
drupal_add_feed('taxonomy/term/' . $term->tid . '/feed', 'RSS - ' . $term->name);
$build = array();
$build['term_heading'] = array(
'#prefix' => '<div class="term-listing-heading">',
'#suffix' => '</div>',
'term' => taxonomy_term_view($term, 'full'),
);
if ($nids = taxonomy_select_nodes($term->tid, TRUE, variable_get('default_nodes_main', 10))) {
$nodes = node_load_multiple($nids);
$build += node_view_multiple($nodes);
$build['pager'] = array(
'#theme' => 'pager',
'#weight' => 5,
);
}
else {
$build['no_content'] = array(
'#prefix' => '<p>',
'#markup' => t('There is currently no content classified with this term.'),
'#suffix' => '</p>',
);
}
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
*/
function i18n_taxonomy_autocomplete_field($field_name, $tags_typed = '') {
// Part of the criteria for the query come from the field's own settings.
$field = field_info_field($field_name);
$vids = array();
$vocabularies = taxonomy_vocabulary_get_names();
foreach ($field['settings']['allowed_values'] as $tree) {
$vids[] = $vocabularies[$tree['vocabulary']]->vid;
}
// This has been redirected from taxonomy module so we add current language and no language
// Because some of the vocabularies may not have language
$langcode = array(i18n_langcode(), LANGUAGE_NONE);
return _i18n_taxonomy_autocomplete($langcode, $vids, $tags_typed);
}
/**
* Helper function for autocompletion. Select by language
*/
function i18n_taxonomy_autocomplete_language($langcode, $vocabulary, $tags_typed = '') {
$vids = $vocabulary ? array($vocabulary->vid) : NULL;
return _i18n_taxonomy_autocomplete($langcode, $vids, $tags_typed);
}
/**
* Helper function for autocompletion
*/
function _i18n_taxonomy_autocomplete($langcode, $vids, $tags_typed = '') {
// The user enters a comma-separated list of tags. We only autocomplete the last tag.
$tags_typed = drupal_explode_tags($tags_typed);
$tag_last = drupal_strtolower(array_pop($tags_typed));
$matches = array();
if ($langcode && $tag_last != '') {
$query = db_select('taxonomy_term_data', 't')
->fields('t', array('tid', 'name'));
$query->addTag('translatable');
$query->addTag('term_access');
// Disable i18n_select for this query
$query->addTag('i18n_select');
// Add language condition
$query->condition('t.language', $langcode);
// Do not select already entered terms.
if (!empty($tags_typed)) {
$query->condition('t.name', $tags_typed, 'NOT IN');
}
// There may be vocabulary restrictions
if ($vids) {
$query->condition('t.vid', $vids);
}
// Select rows that match by term name.
$tags_return = $query
->condition('t.name', '%' . db_like($tag_last) . '%', 'LIKE')
->range(0, 10)
->execute()
->fetchAllKeyed();
$prefix = count($tags_typed) ? drupal_implode_tags($tags_typed) . ', ' : '';
$term_matches = array();
foreach ($tags_return as $tid => $name) {
$n = $name;
// Term names containing commas or quotes must be wrapped in quotes.
if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) {
$n = '"' . str_replace('"', '""', $name) . '"';
}
$term_matches[$prefix . $n] = check_plain($name);
}
}
drupal_json_output($term_matches);
}

View File

@@ -0,0 +1,251 @@
<?php
/**
* @file
* Test case for multilingual taxonomy
*/
class i18nTaxonomyTestCase extends Drupali18nTestCase {
public static function getInfo() {
return array(
'name' => 'Taxonomy translation',
'group' => 'Internationalization',
'description' => 'Taxonomy translation functions'
);
}
function setUp() {
parent::setUp(array('i18n_taxonomy', 'field_test'));
parent::setUpLanguages();
// Create users.
$filtered_html_format = filter_format_load('filtered_html');
$full_html_format = filter_format_load('full_html');
$this->admin_user = $this->drupalCreateUser(array(
'access field_test content',
'administer field_test content',
'administer taxonomy',
'administer languages',
'administer site configuration',
filter_permission_name($filtered_html_format),
filter_permission_name($full_html_format),
));
$this->translator = $this->drupalCreateUser(array('translate interface', 'translate user-defined strings'));
}
function testTaxonomyTermLocalize() {
$this->drupalLogin($this->admin_user);
// Make Input Format "Filter Text" translatable
$edit = array(
'i18n_string_allowed_formats[filtered_html]' => 'filtered_html',
'i18n_string_allowed_formats[plain_text]' => 'plain_text',
);
$this->drupalPost('admin/config/regional/i18n/strings', $edit, t('Save configuration'));
// Create a localizable vocabulary.
$vocab = $this->createVocabulary(array('i18n_mode' => I18N_MODE_LOCALIZE));
$this->assertEqual(i18n_taxonomy_vocabulary_mode($vocab->vid), I18N_MODE_LOCALIZE, 'A vocabulary has been created and it is localizable.');
$this->field_name = $this->createTermField($vocab->machine_name);
// Create a term to be localized. We use a common prefix to facilitate the testing of autocomplete suggestions.
$prefix = $this->randomName() . '_';
$term = $this->createTerm(array('vid' => $vocab->vid, 'name' => $prefix . $this->randomName()));
$this->drupalLogin($this->translator);
// Create and Save Spanish translation, again using the same prefix.
$term_translation = array(
'name' => $this->createStringTranslation('taxonomy', $term->name, array($this->secondary_language => $prefix . $this->randomName())),
'description' => $this->createStringTranslation('taxonomy', $term->description, array($this->secondary_language => $prefix . $this->randomName())),
);
$this->drupalLogin($this->admin_user);
$langcode = LANGUAGE_NONE;
$edit = array(
"{$this->field_name}[$langcode]" => array($term->tid),
);
// Test the widgets in the original language.
$this->drupalGet('test-entity/add/test-bundle');
$this->assertText($term->name, 'Widget values are displayed correctly in default language.');
$this->drupalPost(NULL, $edit, t('Save'));
$this->assertText($term->name, 'Field values are displayed correctly in default language.');
// Terms should be localized in the field widget.
$this->drupalGet($this->secondary_language . '/test-entity/add/test-bundle');
$this->assertText($term_translation['name'][$this->secondary_language], 'Widget values are displayed correctly in non-default languages.');
$this->drupalPost(NULL, $edit, t('Save'));
$this->assertText($term_translation['name'][$this->secondary_language], 'Field values are displayed correctly in non-default languages.');
// Term name and term description should be localized
$this->drupalGet('taxonomy/term/' . $term->tid, array('language' => i18n_language_object($this->default_language)));
$this->assertText($term->name, 'Term title is displayed correctly in default language.');
$this->assertText($term->description, 'Term description is displayed correctly in default language.');
// Term name and term description should be localized
$this->drupalGet('taxonomy/term/' . $term->tid, array('language' => i18n_language_object($this->secondary_language)));
$this->assertText($term_translation['name'][$this->secondary_language], 'Term title is displayed correctly in non-default language.');
$this->assertText($term_translation['description'][$this->secondary_language], 'Term description is displayed correctly in non-default language.');
// Autocomplete should respect localization.
$autocomplete_path = 'taxonomy/autocomplete/' . $this->field_name . '/' . $prefix;
$autocomplete_values = $this->drupalGetAJAX($autocomplete_path);
$this->assertTrue(isset($autocomplete_values[$term->name]), 'Correct autocomplete suggestions in default language.');
$this->assertFalse(isset($autocomplete_values[$term_translation['name'][$this->secondary_language]]), 'No incorrect autocomplete suggestions in non-default languages');
// Autocomplete should respect localization, but doesn't.
// $autocomplete_path = $this->secondary_language . '/taxonomy/autocomplete/' . $this->field_name . '/' . $prefix;
// $autocomplete_values = $this->drupalGetAJAX($autocomplete_path);
// $this->assertFalse(isset($autocomplete_values[$term->name]), 'Correct autocomplete suggestions in non-default languages.');
// $this->assertTrue(isset($autocomplete_values[$term_translation[$this->secondary_language]]), 'No incorrect autocomplete suggestions in non-default languages.');
}
function testTaxonomyTermTranslate() {
// Create a translateable vocabulary.
$vocab = $this->createVocabulary(array('i18n_mode' => I18N_MODE_TRANSLATE));
$this->assertEqual(i18n_taxonomy_vocabulary_mode($vocab->vid), I18N_MODE_TRANSLATE, 'A vocabulary has been created and it is translateable.');
$this->field_select = $this->createTermField($vocab->machine_name);
$this->field_autocomplete = $this->createTermField($vocab->machine_name, 'taxonomy_autocomplete');
// Create a term to be translated.
$en_term = $this->createTerm(array('vid' => $vocab->vid, 'language' => $this->default_language));
$es_term = $this->createTerm(array('vid' => $vocab->vid, 'language' => $this->secondary_language));
$this->drupalLogin($this->admin_user);
// Set terms as translations of each other.
$edit = array(
'translations[' . $this->default_language . ']' => $en_term->name,
'translations[' . $this->secondary_language . ']' => $es_term->name,
);
$this->drupalPost('admin/structure/taxonomy/' . $vocab->machine_name . '/list/sets/add', $edit, t('Save'));
$this->drupalGet('admin/structure/taxonomy/' . $vocab->machine_name . '/list/sets');
// Freetagging creates terms with the correct language.
$new_term_name = $this->randomName();
$langcode = LANGUAGE_NONE;
$edit = array(
"{$this->field_autocomplete}[$langcode]" => $new_term_name,
);
$this->drupalPost($this->secondary_language . '/test-entity/add/test-bundle', $edit, t('Save'));
$new_term = current(taxonomy_get_term_by_name($new_term_name));
$this->assertEqual($new_term->language, $this->secondary_language, 'Freetagging creates terms with the correct language.');
// Term translations are used for language switching.
$language_switcher = language_negotiation_get_switch_links(LANGUAGE_TYPE_INTERFACE, 'taxonomy/term/' . $en_term->tid);
$this->assertEqual($language_switcher->links[$this->secondary_language]['href'], 'taxonomy/term/' . $es_term->tid, 'Term translations are used for language switching.');
}
/**
* Tests the implementation of 'options_list_callback' for term reference fields.
* Enable and disable the callback properly. Avoid WSOD!
*/
function testTaxonomyFieldCallback() {
$field_name = 'taxonomy_term_test_field';
$field = field_create_field(array(
'field_name' => $field_name,
'type' => 'taxonomy_term_reference',
));
$field = field_info_field($field_name);
$callback = 'i18n_taxonomy_allowed_values';
$this->assertTrue(function_exists($callback), "Function $callback exists.");
$this->assertEqual($field['settings']['options_list_callback'], $callback, "$callback ist option list callback.");
module_disable(array('i18n_taxonomy'));
$field = field_info_field($field_name);
$this->assertNotEqual($field['settings']['options_list_callback'], $callback, "$callback ist option list callback.");
}
// Create vocabulary with given fields
function drupalCreateVocabulary($vocab = array()) {
$vocab += array('name' => $this->randomName(10), 'description' => $this->randomName(20));
taxonomy_vocabulary_save($vocab);
return (object)$vocab;
}
// Create term with given fields
function drupalCreateTerms($number = 1, $data = array()) {
$list = array();
for ($i = 1; $i <= $number ; $i++ ) {
$term = $this->createTerm($data);
$list[$term->tid] = $term;
}
return $list;
}
/**
* Returns a new vocabulary with random properties.
*/
function createVocabulary($data = array()) {
// Create a vocabulary.
$data += array(
'i18n_mode' => I18N_MODE_LOCALIZE,
'name' => $this->randomName(),
'description' => $this->randomName(),
'machine_name' => drupal_strtolower($this->randomName()),
'help' => '',
'nodes' => array('article' => 'article'),
'weight' => mt_rand(0, 10),
);
$vocabulary = (object)$data;
taxonomy_vocabulary_save($vocabulary);
return $vocabulary;
}
/**
* Returns a new term with random properties in vocabulary $vid.
*/
function createTerm($data = array()) {
$data += array(
'name' => $this->randomName(),
'description' => $this->randomName(),
// Use the first available text format and vocabulary.
'format' => filter_default_format(),
'vid' => 1,
);
$term = (object)$data;
taxonomy_term_save($term);
return $term;
}
/**
* Setup a field and instance.
*/
function createTermField($machine_name, $widget = 'options_select') {
$field_name = drupal_strtolower($this->randomName());
$this->field = array(
'field_name' => $field_name,
'type' => 'taxonomy_term_reference',
'settings' => array(
'allowed_values' => array(
array(
'vocabulary' => $machine_name,
'parent' => '0',
),
),
)
);
field_create_field($this->field);
$this->instance = array(
'field_name' => $field_name,
'entity_type' => 'test_entity',
'bundle' => 'test_bundle',
'widget' => array(
'type' => $widget,
),
'display' => array(
'full' => array(
'type' => 'taxonomy_term_reference_link',
),
),
);
field_create_instance($this->instance);
return $field_name;
}
}

View File

@@ -0,0 +1,111 @@
<?php
/**
* @file
* Builds placeholder replacement tokens for taxonomy terms and vocabularies.
*/
/**
* Implements hook_token_info().
*/
function i18n_taxonomy_token_info() {
// Taxonomy term related variables.
$term['i18n-name'] = array(
'name' => t("Name (localized)"),
'description' => t("The name of the taxonomy term."),
);
$term['i18n-description'] = array(
'name' => t("Description (localized)"),
'description' => t("The optional description of the taxonomy term."),
);
// Taxonomy vocabulary related variables.
$vocabulary['i18n-name'] = array(
'name' => t("Name (localized)"),
'description' => t("The name of the taxonomy vocabulary."),
);
$vocabulary['i18n-description'] = array(
'name' => t("Description (localized)"),
'description' => t("The optional description of the taxonomy vocabulary."),
);
// Chained tokens for taxonomies
$term['i18n-vocabulary'] = array(
'name' => t("Vocabulary (localized)"),
'description' => t("The vocabulary the taxonomy term belongs to."),
'type' => 'vocabulary',
);
$term['i18n-parent'] = array(
'name' => t("Parent term (localized)"),
'description' => t("The parent term of the taxonomy term, if one exists."),
'type' => 'term',
);
return array(
'tokens' => array(
'term' => $term,
'vocabulary' => $vocabulary,
),
);
}
/**
* Implements hook_tokens().
*/
function i18n_taxonomy_tokens($type, $tokens, array $data = array(), array $options = array()) {
$replacements = array();
$sanitize = !empty($options['sanitize']);
$langcode = isset($options['language']) ? $options['language']->language : i18n_langcode();
if ($type == 'term' && !empty($data['term'])) {
$term = $data['term'];
foreach ($tokens as $name => $original) {
switch ($name) {
case 'i18n-name':
$name = i18n_taxonomy_term_name($term, $langcode);
$replacements[$original] = $sanitize ? check_plain($name) : $name;
break;
case 'i18n-description':
$replacements[$original] = i18n_string_text(array('taxonomy', 'term', $term->tid, 'description'), $term->description, array('langcode' => $langcode, 'format' => $term->format, 'sanitize' => $sanitize, 'cache' => TRUE));
break;
case 'i18n-vocabulary':
$vocabulary = taxonomy_vocabulary_load($term->vid);
$replacements[$original] = check_plain(i18n_taxonomy_vocabulary_name($vocabulary, $langcode));
break;
case 'i18n-parent':
if ($parents = taxonomy_get_parents($term->tid)) {
$parent = array_pop($parents);
$replacements[$original] = check_plain(i18n_taxonomy_term_name($parent, $langcode));
}
break;
}
}
}
elseif ($type == 'vocabulary' && !empty($data['vocabulary'])) {
$vocabulary = $data['vocabulary'];
foreach ($tokens as $name => $original) {
switch ($name) {
case 'i18n-name':
$name = i18n_taxonomy_vocabulary_name($vocabulary, $langcode);
$replacements[$original] = $sanitize ? check_plain($name) : $name;
break;
case 'i18n-description':
$description = i18n_object_langcode($vocabulary) ? $vocabulary->description : i18n_string(array('taxonomy', 'vocabulary', $vocabulary->vid, 'description'), $vocabulary->description, array('langcode' => $langcode));
$replacements[$original] = $sanitize ? filter_xss($description) : $description;
break;
}
}
}
return $replacements;
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* @file
* Views integration for i18n_taxonomy fields.
*/
/**
* Implements hook_field_views_data().
*/
function i18n_taxonomy_field_views_data($field) {
return taxonomy_field_views_data($field);
}
/**
* Implements hook_field_views_data_views_data_alter().
*/
function i18n_taxonomy_field_views_data_views_data_alter(&$data, $field) {
return taxonomy_field_views_data_views_data_alter($data, $field);
}