Newer
Older
Jose Antonio Reyero del Prado
committed
* Internationalization (i18n) package.
* This module groups together all existing i18n taxonomy functionality
* providing several options for taxonomy translation.
* Translates taxonomy term for selected vocabularies running them through the localization system.
* It also translates terms for views filters and views results.
* @author Jose A. Reyero, 2004
*/
* Implements hook_help().
function i18n_taxonomy_help($path, $arg) {
case 'admin/help#i18n_taxonomy' :
$output = '<p>'. t('This module adds support for multilingual taxonomy. You can set up multilingual options for each vocabulary:') .'</p>';
$output .= '<ul>';
$output .= '<li>'. t('A language can be assigned globaly for a vocabulary.') .'</li>';
$output .= '<li>'. t('Different terms for each language with translation relationships.') .'</li>';
$output .= '<li>'. t('Terms can be common to all languages, but may be localized.') .'</li>';
$output .= '</ul>';
$output .= '<p>'. t('To search and translate strings, use the <a href="@translate-interface">translation interface</a> pages.', array('@translate-interface' => url('admin/config/regional/translate'))) .'</p>';
$output .= '<p>'. t('For more information, see the online handbook entry for <a href="@i18n">Internationalization module</a>.', array('@i18n' => 'http://drupal.org/node/133977')) .'</p>';
return $output;
case 'admin/config/regional/i18n':
Jose Antonio Reyero del Prado
committed
$output = '<p>'. t('To set up multilingual options for vocabularies go to <a href="@configure_taxonomy">Taxonomy configuration page</a>.', array('@configure_taxonomy' => url('admin/structure/taxonomy'))) .'</p>';
return $output;
case 'admin/structure/taxonomy/%':
$vocabulary = taxonomy_vocabulary_machine_name_load($arg[3]);
switch (i18n_taxonomy_vocabulary_mode($vocabulary)) {
case I18N_MODE_LOCALIZE:
return '<p>'. t('%capital_name is a localizable vocabulary. You will be able to translate term names and descriptions using the <a href="@translate-interface">translate interface</a> pages.', array('%capital_name' => drupal_ucfirst($vocabulary->name), '%name' => $vocabulary->name, '@translate-interface' => url('admin/config/regional/translate'))) .'</p>';
case I18N_MODE_LANGUAGE:
return '<p>'. t('%capital_name is a vocabulary with a fixed language. All the terms in this vocabulary will have %language language.', array('%capital_name' => drupal_ucfirst($vocabulary->name), '%name' => $vocabulary->name, '%language' => i18n_language_property($vocabulary->language, 'name'))) .'</p>';
case I18N_MODE_TRANSLATE:
return '<p>'. t('%capital_name is a full multilingual vocabulary. You will be able to set a language for each term and create translation relationships.', array('%capital_name' => drupal_ucfirst($vocabulary->name))) .'</p>';
* Implements hook_menu().
function i18n_taxonomy_menu() {
Gábor Hojtsy
committed
$items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/list/list'] = array(
'title' => 'Terms',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -20,
);
$items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/list/sets'] = array(
'title' => 'Translation sets',
'page callback' => 'i18n_taxonomy_translation_sets_overview',
'page arguments' => array(3),
'access callback' => 'i18n_taxonomy_vocabulary_translation_tab_sets_access',
'access arguments' => array(3),
'type' => MENU_LOCAL_TASK,
'file' => 'i18n_taxonomy.admin.inc',
);
$items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/list/sets/add'] = array(
'title' => 'Create new translation',
'page callback' => 'drupal_get_form',
'page arguments' => array('i18n_taxonomy_translation_term_form', 3),
Gábor Hojtsy
committed
'access callback' => 'i18n_taxonomy_vocabulary_translation_tab_sets_access',
'access arguments' => array(3),
'type' => MENU_LOCAL_ACTION,
//'parent' => 'admin/content/taxonomy/%taxonomy_vocabulary',
'file' => 'i18n_taxonomy.admin.inc',
);
Gábor Hojtsy
committed
$items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/list/sets/edit/%i18n_taxonomy_translation_set'] = array(
'title' => 'Edit translation',
'page callback' => 'drupal_get_form',
Gábor Hojtsy
committed
'page arguments' => array('i18n_taxonomy_translation_term_form', 3, 7),
'access callback' => 'i18n_taxonomy_vocabulary_translation_tab_sets_access',
'access arguments' => array(3),
'type' => MENU_CALLBACK,
//'parent' => 'admin/content/taxonomy/%taxonomy_vocabulary',
'file' => 'i18n_taxonomy.admin.inc',
);
Jose Antonio Reyero del Prado
committed
$items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/list/sets/delete/%i18n_taxonomy_translation_set'] = array(
'title' => 'Delete translation',
'page callback' => 'drupal_get_form',
'page arguments' => array('i18n_translation_set_delete_confirm', 7),
'access callback' => 'i18n_taxonomy_vocabulary_translation_tab_sets_access',
'access arguments' => array(3),
'type' => MENU_CALLBACK,
);
$items['i18n/taxonomy/autocomplete/vocabulary/%taxonomy_vocabulary_machine_name/%'] = array(
'title' => 'Autocomplete taxonomy',
'page callback' => 'i18n_taxonomy_autocomplete_language',
'page arguments' => array(5, 4),
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
'file' => 'i18n_taxonomy.pages.inc',
);
$items['i18n/taxonomy/autocomplete/language/%'] = array(
'title' => 'Autocomplete taxonomy',
'page callback' => 'i18n_taxonomy_autocomplete_language',
'page arguments' => array(4, NULL),
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
'file' => 'i18n_taxonomy.pages.inc',
);
/**
* Implements hook_admin_paths().
*/
function i18n_taxonomy_admin_paths() {
$paths = array(
'taxonomy/*/translate' => TRUE,
'taxonomy/*/translate/*' => TRUE,
);
return $paths;
}
/**
* Implements hook_menu_alter().
* Take over the taxonomy pages
*/
function i18n_taxonomy_menu_alter(&$items) {
Jose Antonio Reyero del Prado
committed
// If ctool's page manager is active for the path skip this modules override.
Jose Antonio Reyero del Prado
committed
// Also views module takes over this page so this won't work if views enabled.
Jose Antonio Reyero del Prado
committed
if (variable_get('page_manager_term_view_disabled', TRUE)) {
// Taxonomy term page. Localize terms.
$items['taxonomy/term/%taxonomy_term']['page callback'] = 'i18n_taxonomy_term_page';
Jose Antonio Reyero del Prado
committed
$items['taxonomy/term/%taxonomy_term']['title callback'] = 'i18n_taxonomy_term_name';
$items['taxonomy/term/%taxonomy_term']['file'] = 'i18n_taxonomy.pages.inc';
Jose Antonio Reyero del Prado
committed
$items['taxonomy/term/%taxonomy_term']['module'] = 'i18n_taxonomy';
Jose Antonio Reyero del Prado
committed
}
// Localize autocomplete
$items['taxonomy/autocomplete']['page callback'] = 'i18n_taxonomy_autocomplete_field';
$items['taxonomy/autocomplete']['file'] = 'i18n_taxonomy.pages.inc';
Jose Antonio Reyero del Prado
committed
$items['taxonomy/autocomplete']['module'] = 'i18n_taxonomy';
}
Gábor Hojtsy
committed
/**
* Menu access callback for vocabulary translation tab. Show tab only for full multilingual vocabularies.
*/
function i18n_taxonomy_vocabulary_translation_tab_sets_access($vocabulary) {
Jose Antonio Reyero del Prado
committed
return user_access('administer taxonomy') && i18n_taxonomy_vocabulary_mode($vocabulary->vid, I18N_MODE_TRANSLATE);
}
/**
* Menu access callback for term translation tab. Show tab only for translatable terms
*
Jose Antonio Reyero del Prado
committed
* @todo This should work also for localizable terms when we've got that part implemented
*/
function i18n_taxonomy_term_translation_tab_access($term) {
Sascha Grossenbacher
committed
return taxonomy_term_edit_access($term) && i18n_taxonomy_vocabulary_mode($term->vid) & I18N_MODE_MULTIPLE && user_access('translate interface');
}
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/**
* Implements hook_field_formatter_info().
*/
function i18n_taxonomy_field_formatter_info() {
return array(
'i18n_taxonomy_term_reference_link' => array(
'label' => t('Link (localized)'),
'field types' => array('taxonomy_term_reference'),
),
'i18n_taxonomy_term_reference_plain' => array(
'label' => t('Plain text (localized)'),
'field types' => array('taxonomy_term_reference'),
),
);
}
/**
* Implements hook_field_formatter_prepare_view().
*
* This preloads all taxonomy terms for multiple loaded objects at once and
* unsets values for invalid terms that do not exist.
*/
function i18n_taxonomy_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
return taxonomy_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, $items, $displays);
}
/**
* Implements hook_field_formatter_view().
*/
function i18n_taxonomy_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
$element = array();
Florian Weber
committed
$language = i18n_language();
// Terms whose tid is 'autocreate' do not exist
// yet and $item['taxonomy_term'] is not set. Theme such terms as
// just their name.
switch ($display['type']) {
case 'i18n_taxonomy_term_reference_link':
foreach ($items as $delta => $item) {
if ($item['tid'] == 'autocreate') {
$element[$delta] = array(
'#markup' => check_plain($item['name']),
);
}
else {
$term = $item['taxonomy_term'];
$uri = entity_uri('taxonomy_term', $term);
$element[$delta] = array(
'#type' => 'link',
Florian Weber
committed
'#title' => i18n_taxonomy_term_name($term, $language->language),
'#href' => $uri['path'],
'#options' => $uri['options'],
);
}
}
break;
case 'i18n_taxonomy_term_reference_plain':
foreach ($items as $delta => $item) {
Florian Weber
committed
$name = ($item['tid'] != 'autocreate' ? i18n_taxonomy_term_name($item['taxonomy_term'], $language->language): $item['name']);
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
$element[$delta] = array(
'#markup' => check_plain($name),
);
}
break;
}
return $element;
}
/**
* Implements hook_field_extra_fields().
*/
function i18n_taxonomy_field_extra_fields() {
$return = array();
$info = entity_get_info('taxonomy_term');
foreach (array_keys($info['bundles']) as $bundle) {
$vocabulary = taxonomy_vocabulary_machine_name_load($bundle);
if (i18n_taxonomy_vocabulary_mode($vocabulary, I18N_MODE_TRANSLATE)) {
$return['taxonomy_term'][$bundle] = i18n_language_field_extra();
}
}
return $return;
}
/**
* Implements hook_field_attach_view_alter().
*/
function i18n_taxonomy_field_attach_view_alter(&$output, $context) {
if ($context['entity_type'] == 'taxonomy_term' && i18n_taxonomy_vocabulary_mode($context['entity']->vid, I18N_MODE_TRANSLATE)) {
$output['language'] = array(
'#type' => 'item',
'#title' => t('Language'),
'#markup' => i18n_language_name($context['entity']->language),
);
}
}
/**
* Implements hook_field_info_alter()
*/
function i18n_taxonomy_field_info_alter(&$info) {
// Change default formatter for term reference fields
$info['taxonomy_term_reference']['default_formatter'] = 'i18n_taxonomy_term_reference_link';
// Change module for this field. Basically we take over this field and this means
// we need to implement a bunch of hooks for fields and options, including hook_field_schema()
$info['taxonomy_term_reference']['module'] = 'i18n_taxonomy';
Jose Antonio Reyero del Prado
committed
// Sync callback for field translations
$info['taxonomy_term_reference']['i18n_sync_callback'] = 'i18n_taxonomy_field_prepare_translation';
}
/**
* Implements hook_field_prepare_translation().
*
* Prepare and synchronize translation for term reference fields
*/
function i18n_taxonomy_field_prepare_translation($entity_type, $entity, $field, $instance, $langcode, &$items, $source_entity, $source_langcode) {
foreach ($items as $index => $item) {
$term = isset($item['taxonomy_term']) ? $item['taxonomy_term'] : taxonomy_term_load($item['tid']);
if ($translation = i18n_taxonomy_term_get_translation($term, $langcode)) {
$items[$index] = array(
'taxonomy_term' => $translation,
'tid' => $translation->tid
);
}
}
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
}
/**
* Implements hook_field_is_empty().
*/
function i18n_taxonomy_field_is_empty($item, $field) {
return taxonomy_field_is_empty($item, $field);
}
/**
* Implements hook_field_widget_error().
*/
function i18n_taxonomy_field_widget_error($element, $error, $form, &$form_state) {
form_error($element, $error['message']);
}
/**
* Implements hook_field_widget_form().
*/
function i18n_taxonomy_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
return taxonomy_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $element);
}
/**
* Implements hook_field_settings_form().
*/
function i18n_taxonomy_field_settings_form($field, $instance, $has_data) {
return taxonomy_field_settings_form($field, $instance, $has_data);
}
/**
* Implements hook_field_validate().
*/
function i18n_taxonomy_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
return taxonomy_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, $errors);
}
/**
* Implements hook_field_presave().
*
* Create any new terms defined in a freetagging vocabulary.
*/
function i18n_taxonomy_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
return taxonomy_field_presave($entity_type, $entity, $field, $instance, $langcode, $items);
}
/**
* Implements hook_field_insert().
*/
function i18n_taxonomy_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
return taxonomy_field_insert($entity_type, $entity, $field, $instance, $langcode, $items);
}
/**
* Implements hook_field_update().
*/
function i18n_taxonomy_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
return taxonomy_field_update($entity_type, $entity, $field, $instance, $langcode, $items);
}
/**
* Implements hook_options_list().
*/
function i18n_taxonomy_options_list($field) {
$function = !empty($field['settings']['options_list_callback']) ? $field['settings']['options_list_callback'] : 'i18n_taxonomy_allowed_values';
return $function($field);
}
/**
* Returns the set of valid terms for a taxonomy field.
*
* @param $field
* The field definition.
* @return
* The array of valid terms for this field, keyed by term id.
*/
function i18n_taxonomy_allowed_values($field) {
$options = array();
foreach ($field['settings']['allowed_values'] as $tree) {
if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
if ($terms = taxonomy_get_tree($vocabulary->vid, $tree['parent'])) {
foreach ($terms as $term) {
$options[$term->tid] = str_repeat('-', $term->depth) . i18n_taxonomy_term_name($term);
}
}
}
}
return $options;
}
/**
* Implements hook_i18n_translate_path()
*/
function i18n_taxonomy_i18n_translate_path($path, $language) {
if ($translations = i18n_taxonomy_translate_path($path, array($language->language))) {
return reset($translations);
}
}
* Implements hook_language_switch_links_alter().
*
* Replaces links with pointers to translated versions of the content.
*/
function i18n_taxonomy_language_switch_links_alter(array &$links, $type, $path) {
if ($translations = i18n_taxonomy_translate_path($path, array_keys($links))) { //or at a taxonomy-listing?
foreach ($translations as $langcode => $translated_path) {
$links[$langcode]['href'] = $translated_path;
}
}
}
/**
* Translate path to languages
*
* @param $path
* Path to translate
* @param $languages
* Language codes
*/
function i18n_taxonomy_translate_path($path, $languages) {
$cache = &drupal_static(__FUNCTION__);
if (preg_match("/^(taxonomy\/term\/)([^\/]*)(.*)$/", $path, $matches)) { //or at a taxonomy-listing?
$translations = array();
foreach ($languages as $langcode) {
if (isset($cache[$path][$langcode])) {
$translations[$langcode] = $cache[$path][$langcode];
}
elseif ($str_tids = i18n_taxonomy_translation_tids($matches[2], $langcode)) {
$translations[$langcode] = $cache[$path][$langcode] = "taxonomy/term/$str_tids". $matches[3];
return $translations;
}
Jose Antonio Reyero del Prado
committed
/**
* Implements hook_theme().
Jose Antonio Reyero del Prado
committed
*/
function i18n_taxonomy_theme() {
Jose Antonio Reyero del Prado
committed
return array(
'i18n_taxonomy_term_page' => array(
Jose Antonio Reyero del Prado
committed
'arguments' => array('tids' => array(), 'result' => NULL),
'file' => 'i18n_taxonomy.pages.inc',
Jose Antonio Reyero del Prado
committed
),
);
}
/**
Jose Antonio Reyero del Prado
committed
*/
function i18n_taxonomy_term_name($term, $langcode = NULL) {
return i18n_taxonomy_vocabulary_mode($term->vid, I18N_MODE_LOCALIZE) ? i18n_string(array('taxonomy', 'term', $term->tid, 'name'), $term->name, array('langcode' => $langcode)) : $term->name;
Jose Antonio Reyero del Prado
committed
}
Jose Antonio Reyero del Prado
committed
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
/**
* Find term translation from translation set.
*
* @param $term
* Term object to find translation.
* @param $langcode
* Language code to find translation for.
* @result object Taxonomy Term
* Translation if exists.
*/
function i18n_taxonomy_term_get_translation($term, $langcode) {
if (i18n_object_langcode($term)) {
if ($term->language == $langcode) {
// Translation is the term itself.
return $term;
}
elseif (!empty($term->i18n_tsid)) {
return i18n_translation_set_load($term->i18n_tsid)->get_item($langcode);
}
else {
return NULL;
}
}
else {
// Term has no language, translation should be the same
return $term;
}
}
Jose Antonio Reyero del Prado
committed
/**
Jose Antonio Reyero del Prado
committed
*/
function i18n_taxonomy_vocabulary_name($vocabulary, $langcode = NULL) {
return i18n_object_langcode($vocabulary) ? $vocabulary->name : i18n_string(array('taxonomy', 'vocabulary', $vocabulary->vid, 'name'), $vocabulary->name, array('langcode' => $langcode));
Jose Antonio Reyero del Prado
committed
}
* Node nid to search for translation.
* Language to search for the translation, defaults to current language.
* Value that will be returned if no translation is found.
* Translated term tid if exists, or $default.
function i18n_taxonomy_translation_term_tid($tid, $language = NULL, $default = NULL) {
$translation = db_query('SELECT t.tid FROM {taxonomy_term_data} t INNER JOIN {taxonomy_term_data} a ON t.i18n_tsid = a.i18n_tsid AND t.tid <> a.tid WHERE a.tid = :tid AND t.language = :language AND t.i18n_tsid > 0', array(
':tid' => $tid,
':language' =>$language ? $language : i18n_language()->language
))->fetchField();
return $translation ? $translation : $default;
}
/**
* Returns an url for the translated taxonomy-page, if exists.
function i18n_taxonomy_translation_tids($str_tids, $lang) {
if (preg_match('/^([0-9]+[+ ])+[0-9]+$/', $str_tids)) {
$separator = '+';
// The '+' character in a query string may be parsed as ' '.
$tids = preg_split('/[+ ]/', $str_tids);
}
elseif (preg_match('/^([0-9]+,)*[0-9]+$/', $str_tids)) {
$separator = ',';
$tids = explode(',', $str_tids);
}
else {
return;
}
$translated_tids = array();
foreach ($tids as $tid) {
if ($translated_tid = i18n_taxonomy_translation_term_tid($tid, $lang)) {
$translated_tids[] = $translated_tid;
}
}
return implode($separator, $translated_tids);
}
* Implements hook_taxonomy_term_insert()
function i18n_taxonomy_taxonomy_term_insert($term) {
i18n_taxonomy_taxonomy_term_update($term);
}
/**
* Implements hook_taxonomy_term_update()
*/
Jose Antonio Reyero del Prado
committed
function i18n_taxonomy_taxonomy_term_update($term) {
if (i18n_taxonomy_vocabulary_mode($term->vid, I18N_MODE_LOCALIZE)) {
i18n_string_object_update('taxonomy_term', $term);
}
Jose Antonio Reyero del Prado
committed
// Multilingual terms, translatable. Link / unlink from translation set.
if (i18n_taxonomy_vocabulary_mode($term->vid, I18N_MODE_TRANSLATE) && !empty($term->translation_set)) {
if (i18n_object_langcode($term)) {
$term->translation_set
->add_item($term)
->save();
}
elseif (!empty($term->original)) {
// Term set to language neutral, remove it from translation set and update set (delete if empty)
$term->translation_set
->remove_item($term->original)
->update_delete();
}
}
}
/**
* Implements hook_taxonomy_term_delete()
*/
function i18n_taxonomy_taxonomy_term_delete($term) {
Jose Antonio Reyero del Prado
committed
// If a translation set exists for this term, remove this term from the set.
if (isset($term->i18n_tsid) && $term->i18n_tsid) {
$translation_set = i18n_translation_set_load($term->i18n_tsid);
$translation_set->get_translations();
$translation_set->remove_language($term->language);
Jose Antonio Reyero del Prado
committed
// If there are no terms left in this translation set, delete the set.
// Otherwise update the set.
$translation_set->update_delete();
Jose Antonio Reyero del Prado
committed
}
// Just in case there's any left over string we run it for all terms.
i18n_string_object_remove('taxonomy_term', $term);
}
Jose Antonio Reyero del Prado
committed
/**
* Implements hook_taxonomy_vocabulary_insert()
*/
function i18n_taxonomy_taxonomy_vocabulary_insert($vocabulary) {
i18n_taxonomy_taxonomy_vocabulary_update($vocabulary);
}
/**
* Implements hook_taxonomy_vocabulary_update()
*/
Jose Antonio Reyero del Prado
committed
function i18n_taxonomy_taxonomy_vocabulary_update($vocabulary) {
// Update language for related terms
switch ($vocabulary->i18n_mode) {
case I18N_MODE_LANGUAGE:
$update['language'] = $vocabulary->language;
break;
case I18N_MODE_NONE:
$update['language'] = LANGUAGE_NONE;
Jose Antonio Reyero del Prado
committed
break;
}
if (isset($update)) {
db_update('taxonomy_term_data')
->fields($update)
->condition('vid', $vocabulary->vid)
->execute();
drupal_set_message(t('Reset language for all terms.'));
}
// Update strings, always add translation if no language
if (!i18n_object_langcode($vocabulary)) {
i18n_string_object_update('taxonomy_vocabulary', $vocabulary);
}
}
/**
Jose Antonio Reyero del Prado
committed
* Implements hook_taxonomy_vocabulary_delete()
*/
function i18n_taxonomy_taxonomy_vocabulary_delete($vocabulary) {
i18n_string_object_remove('taxonomy_vocabulary', $vocabulary);
}
Jose Antonio Reyero del Prado
committed
/**
* Implements hook_taxonomy_term_presave()
*/
function i18n_taxonomy_taxonomy_term_presave($term) {
switch (i18n_taxonomy_vocabulary_mode($term->vid)) {
case I18N_MODE_LANGUAGE; // Predefined language for all terms
$term->language = taxonomy_vocabulary_load($term->vid)->language;
Jose Antonio Reyero del Prado
committed
break;
case I18N_MODE_TRANSLATE: // Multilingual terms, translatable
if (!isset($term->language)) {
// The term may come from a node tags field, just if this is not a taxonomy form
$term->language = i18n_langcode();
}
// Only for the case the term has no language, it may need to be removed from translation set
if (empty($term->language)) {
$term->trid = 0;
}
break;
}
}
Jose Antonio Reyero del Prado
committed
/**
* Implements hook_form_FORM_ID_alter()
*/
function i18n_taxonomy_form_taxonomy_form_vocabulary_alter(&$form, &$form_state) {
Jose Antonio Reyero del Prado
committed
if (!isset($form_state['confirm_delete'])) {
$vocabulary = $form_state['vocabulary'];
$i18n_mode = i18n_taxonomy_vocabulary_mode($vocabulary);
$langcode = i18n_object_langcode($vocabulary, LANGUAGE_NONE);
Jose Antonio Reyero del Prado
committed
// Define the replacement names to add some logic to the translation mode options.
$form += i18n_translation_mode_element('taxonomy_vocabulary', $i18n_mode, $langcode);
Sascha Grossenbacher
committed
if (user_access('translate interface')) {
$form['actions']['translate'] = array(
'#type' => 'submit',
'#name' => 'save_translate',
'#value' => t('Save and translate'),
'#weight' => 5,
'#states' => array(
'invisible' => array(
// Hide the button if language mode is selected value needs to be a
// string so that the javascript-side matching works.
'input[name=i18n_mode]' => array('value' => (string)I18N_MODE_LANGUAGE),
)
)
);
// Make sure the delete buttons shows up last.
if (isset($form['actions']['delete'])) {
$form['actions']['delete']['#weight'] = 10;
}
}
Jose Antonio Reyero del Prado
committed
$form['#validate'][] = 'i18n_taxonomy_form_vocabulary_validate';
Sascha Grossenbacher
committed
$form['#submit'][] = 'i18n_taxonomy_form_vocabulary_submit';
Jose Antonio Reyero del Prado
committed
}
Sascha Grossenbacher
committed
/**
* Form submit callback to redirect when using the save and translate button.
*/
function i18n_taxonomy_form_vocabulary_submit($form, &$form_state) {
if ($form_state['triggering_element']['#name'] == 'save_translate') {
$form_state['redirect'] = 'admin/structure/taxonomy/' . $form_state['values']['machine_name'] . '/translate';
Jose Antonio Reyero del Prado
committed
}
* Implements hook_form_FORM_ID_alter()
function i18n_taxonomy_form_taxonomy_form_term_alter(&$form, &$form_state) {
// Check for confirmation forms
if (isset($form_state['confirm_delete']) || isset($form_state['confirm_parents'])) return;
$term = $form_state['term'];
$vocabulary = $form['#vocabulary'];
// Mark form so we can know later when saving the term it came from a taxonomy form
$form['i18n_taxonomy_form'] = array('#type' => 'value', '#value' => 1);
// Add language field or not depending on taxonomy mode.
switch (i18n_taxonomy_vocabulary_mode($vocabulary->vid)) {
case I18N_MODE_TRANSLATE:
$form['language'] = array(
'#description' => t('This term belongs to a multilingual vocabulary. You can set a language for it.'),
) + i18n_element_language_select($term);
// If the term to be added will be a translation of a source term,
// set the default value of the option list to the target language and
// create a form element for storing the translation set of the source term.
if (isset($_GET['translation']) && isset($_GET['target'])) {
$source_term = taxonomy_term_load($_GET['translation']);
// Add the translation set to the form so we know the new term
// needs to be added to that set.
if (!empty($source_term->i18n_tsid)) {
Jose Antonio Reyero del Prado
committed
$translation_set = i18n_taxonomy_translation_set_load($source_term->i18n_tsid);
}
else {
// No translation set yet, build a new one with the source term.
$translation_set = i18n_translation_set_create('taxonomy_term', $vocabulary->machine_name)
->add_item($source_term);
}
$form['language']['#default_value'] = $_GET['target'];
$form['language']['#disabled'] = TRUE;
drupal_set_title(t('%language translation of term %title', array('%language' => locale_language_name($_GET['target']), '%title' => $source_term->name)), PASS_THROUGH);
}
Jose Antonio Reyero del Prado
committed
elseif (i18n_object_langcode($term) && !empty($term->i18n_tsid)) {
// If the current term is part of a translation set,
// remove all other languages of the option list.
$translation_set = i18n_taxonomy_translation_set_load($term->i18n_tsid);
Florian Weber
committed
$translations = $translation_set->get_translations();
// If the number of translations equals 1, there's only a source translation.
if (count($translations) > 1) {
Jose Antonio Reyero del Prado
committed
//unset($form['language']['#options'][LANGUAGE_NONE]);
foreach ($translations as $langcode => $translation) {
if ($translation->tid !== $term->tid) {
unset($form['language']['#options'][$langcode]);
}
}
Jose Antonio Reyero del Prado
committed
$form['language']['#description'] = t('This term already belongs to a <a href="@term-translation">translation set</a>. Changing language to <i>Language neutral</i> will remove it from the set.', array('@term-translation' => url('taxonomy/term/' . $term->tid . '/translate')));
}
}
Jose Antonio Reyero del Prado
committed
// If we've got a translation set, add it to the form.
if (!empty($translation_set)) {
$form['translation_set'] = array(
'#type' => 'value',
'#value' => $translation_set,
);
}
break;
case I18N_MODE_LANGUAGE:
$form['language'] = array(
'#type' => 'value',
'#value' => $vocabulary->language
);
$form['identification']['language_info'] = array('#value' => t('All terms in this vocabulary have a fixed language: %language', array('%language' => i18n_language_name($vocabulary->language))));
break;
case I18N_MODE_LOCALIZE:
$form['language'] = array(
'#type' => 'value',
);
break;
case I18N_MODE_NONE:
default:
$form['language'] = array(
'#type' => 'value',
);
break;
Sascha Grossenbacher
committed
if (user_access('translate interface') && i18n_taxonomy_vocabulary_mode($vocabulary->vid) & I18N_MODE_MULTIPLE) {
$form['actions']['translate'] = array(
'#type' => 'submit',
'#name' => 'save_translate',
'#value' => t('Save and translate'),
'#weight' => 5,
'#states' => array(
'invisible' => array(
// Hide the button if term is language neutral.
'select[name=language]' => array('value' => LANGUAGE_NONE),
),
),
Sascha Grossenbacher
committed
);
// Make sure the delete buttons shows up last.
if (isset($form['actions']['delete'])) {
$form['actions']['delete']['#weight'] = 10;
}
$form['#submit'][] = 'i18n_taxonomy_form_term_submit';
}
}
/**
* Form submit callback to redirect when using the save and translate button.
*/
function i18n_taxonomy_form_term_submit($form, &$form_state) {
if ($form_state['triggering_element']['#name'] == 'save_translate') {
// When using the edit link on the list terms, a destination param is
// added that needs to be unset to make the redirection work.
unset($_GET['destination']);
$form_state['redirect'] = 'taxonomy/term/' . $form_state['values']['tid'] . '/translate';
}
* Implements hook_form_alter().
* This is the place to add language fields to all forms.
* @ TO DO The vocabulary form needs some javascript.
function i18n_taxonomy_form_alter(&$form, $form_state, $form_id) {
Jose Antonio Reyero del Prado
committed
switch ($form_id) {
case 'taxonomy_overview_vocabularies':
$vocabularies = taxonomy_get_vocabularies();
foreach ($vocabularies as $vocabulary) {
if (i18n_object_langcode($vocabulary)) {
$form[$vocabulary->vid]['name']['#markup'] .= ' ('. i18n_language_name($vocabulary->language) .')';
case 'taxonomy_overview_terms':
Jose Antonio Reyero del Prado
committed
// We check for vocabulary object first, because when confirming alphabetical ordering it uses the same form
if (!empty($form['#vocabulary']) && i18n_taxonomy_vocabulary_mode($form['#vocabulary']->vid) & I18N_MODE_TRANSLATE) {
foreach (element_children($form) as $key) {
if (isset($form[$key]['#term']) && ($lang = i18n_object_langcode($form[$key]['#term']))) {
$form[$key]['view']['#suffix'] = ' ('. i18n_language_name($lang) .')';
Jose Antonio Reyero del Prado
committed
case 'search_form':
// Localize category selector in advanced search form.
Jose Antonio Reyero del Prado
committed
if (!empty($form['advanced']) && !empty($form['advanced']['category'])) {
i18n_taxonomy_form_all_localize($form['advanced']['category']);
Jose Antonio Reyero del Prado
committed
}
break;
/**
* Validate multilingual options for vocabulary form
*/
function i18n_taxonomy_form_vocabulary_validate($form, &$form_state) {
Jose Antonio Reyero del Prado
committed
if ($form_state['values']['i18n_mode'] & I18N_MODE_LANGUAGE) {
if ($form_state['values']['language'] == LANGUAGE_NONE) {
form_set_error('language', t('If selecting "Set language to vocabulary" you need to set a language to this vocabulary. Either change the translation mode or select a language.'));
}
Jose Antonio Reyero del Prado
committed
}
Jose Antonio Reyero del Prado
committed
else {
$form_state['values']['language'] = LANGUAGE_NONE;
Jose Antonio Reyero del Prado
committed
}
}
Jose Antonio Reyero del Prado
committed
/**
* Localize a taxonomy_form_all() kind of control
Jose Antonio Reyero del Prado
committed
* The options array is indexed by vocabulary name and then by term id, with tree structure
* We just need to localize vocabulary name and localizable terms. Multilingual vocabularies
* should have been taken care of by query rewriting.
**/
function i18n_taxonomy_form_all_localize(&$item) {
Jose Antonio Reyero del Prado
committed
$options = &$item['#options'];
foreach (taxonomy_get_vocabularies() as $vid => $vocabulary) {
if (!empty($options[$vocabulary->name])) {
// Localize vocabulary name if translated
$vname = i18n_taxonomy_vocabulary_name($vocabulary);
Jose Antonio Reyero del Prado
committed
if ($vname != $vocabulary->name) {
$options[$vname] = $options[$vocabulary->name];
unset($options[$vocabulary->name]);
}
if (i18n_taxonomy_vocabulary_mode($vid) & I18N_MODE_LOCALIZE) {
Jose Antonio Reyero del Prado
committed
$tree = taxonomy_get_tree($vid);
if ($tree && (count($tree) > 0)) {
foreach ($tree as $term) {
if (isset($options[$vname][$term->tid])) {
$options[$vname][$term->tid] = str_repeat('-', $term->depth) . i18n_taxonomy_term_name($term);
Jose Antonio Reyero del Prado
committed
}
Jose Antonio Reyero del Prado
committed
}
}
}
Jose Antonio Reyero del Prado
committed
}
/**
* Find all terms associated with the given node, ordered by vocabulary and term weight.
*
* Same as taxonomy_node_get_terms() but without static caching.
*/
function i18n_taxonomy_node_get_terms($node, $key = 'tid') {
$result = db_query(db_rewrite_sql('SELECT t.* FROM {term_node} r INNER JOIN {term_data} t ON r.tid = t.tid INNER JOIN {vocabulary} v ON t.vid = v.vid WHERE r.vid = %d ORDER BY v.weight, t.weight, t.name', 't', 'tid'), $node->vid);
$terms = array();
while ($term = db_fetch_object($result)) {
$terms[$term->$key] = $term;
}
return $terms;
}
* Translate an array of taxonomy terms.
* Translates all terms with language, just passing over terms without it.
Jose Antonio Reyero del Prado
committed
* Filter out terms with a different language
*
Jose Antonio Reyero del Prado
committed
* @param $taxonomy
* Array of term objects or tids or multiple arrays or terms indexed by vid
* @param $langcode
* Language code of target language
* @param $fullterms
* Whether to return full $term objects, returns tids otherwise
* @return
* Array with translated terms: tid -> $term
* Array with vid and term array
function i18n_taxonomy_translate_terms($taxonomy, $langcode, $fullterms = TRUE) {
if (is_array($taxonomy) && $taxonomy) {
Jose Antonio Reyero del Prado
committed
foreach ($taxonomy as $index => $tdata) {
if (is_array($tdata)) {
// Case 1: Index is vid, $tdata is an array of terms
$mode = i18n_taxonomy_vocabulary_mode($index);
Jose Antonio Reyero del Prado
committed
// We translate just some vocabularies: translatable, fixed language
// Fixed language ones may have terms translated, though the UI doesn't support it
Jose Antonio Reyero del Prado
committed
if ($mode & I18N_MODE_LANGUAGE || $mode & I18N_MODE_TRANSLATE) {
$translation[$index] = i18n_taxonomy_translate_terms($tdata, $langcode, $fullterms);
Jose Antonio Reyero del Prado
committed
}
elseif ($fullterms) {
$translation[$index] = array_map('_i18n_taxonomy_filter_terms', $tdata);
Jose Antonio Reyero del Prado
committed
}
else {
$translation[$index] = array_map('_i18n_taxonomy_filter_tids', $tdata);
Jose Antonio Reyero del Prado
committed
}
continue;
}
elseif (is_object($tdata)) {
// Case 2: This is a term object
$term = $tdata;
}
elseif (is_numeric($tdata) && ($tid = (int)$tdata)) {
Jose Antonio Reyero del Prado
committed
// Case 3: This is a term tid, load the full term
Jose Antonio Reyero del Prado
committed
$term = taxonomy_term_load($tid);
}
// Translate the term if we got it
if (empty($term)) {
// Couldn't identify term, pass through whatever it is
$translation[$index] = $tdata;
Jose Antonio Reyero del Prado
committed
}
elseif ($term->language && $term->language != $langcode) {
Florian Weber
committed
$translation_set = i18n_translation_set_load($term->i18n_tsid);
$translations = $translation_set->get_translations();
if ($translations && !empty($translations[$langcode])) {
$newterm = $translations[$langcode];
Jose Antonio Reyero del Prado
committed
$translation[$newterm->tid] = $fullterms ? $newterm : $newterm->tid;
}
else {
// Term has no language. Should be ok.
Jose Antonio Reyero del Prado
committed
$translation[$index] = $fullterms ? $term : $term->tid;
}
}
}
return $translation;
}
* Localize taxonomy terms for localizable vocabularies.
Jose Antonio Reyero del Prado
committed
* Array of term objects or term object.
* Array of terms with the right ones localized.
Jose Antonio Reyero del Prado
committed
function i18n_taxonomy_localize_terms($terms) {
// If not localizable language just return. Performance optimizations.
if (!i18n_string_translate_langcode()) {
return $terms;
}
Jose Antonio Reyero del Prado
committed
$object_info = i18n_object_info('taxonomy_term');
Jose Antonio Reyero del Prado
committed
$list = is_array($terms) ? $terms : array($terms);
foreach ($list as $index => $term) {
Jose Antonio Reyero del Prado
committed
if (i18n_taxonomy_vocabulary_mode($term->vid, I18N_MODE_LOCALIZE)) {
Jose Antonio Reyero del Prado
committed
$localize[$index] = $term->tid;
Jose Antonio Reyero del Prado
committed
// If multiple terms, preload all translations, then run object translation.
if (!empty($localize)) {
i18n_string_translation_search(array('taxonomy', 'term', $localize, '*'));
foreach ($localize as $index => $tid) {
$list[$index] = i18n_string_object_translate('taxonomy_term', $list[$index]);
}
}