Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
// $Id$
/**
* Internationalization (i18n) package.
*
* Translation module: translation
*
* @author Jose A. Reyero, 2004, http://www.reyero.net
*
*/
/**
* Implementation of hook_help().
*/
function translation_help($section = 'admin/help#translation' ) {
switch ($section) {
case 'admin/help#translation' :
$output = t('
<p>This module is part of i18n package and provides support for translation relationships.</p>
<p>The objects you can define translation relationships for are:</p>
<ul>
<li>Nodes</li>
<li>Taxonomy Terms</li>
</ul>
<p><small>Module developed by Jose A. Reyero, <a href="http://www.reyero.net">www.reyero.net</a></small></p>' );
break;
case 'admin/modules#description' :
$output = t('Manages translations between nodes and taxonomy terms. <b>Requires i18n module</b>' );
break;
case 'admin/access#translation':
$output = t('<h2>Translations</h2>');
$output = t('<strong>translate nodes</strong> <p>This one, combined with create content permissions, will allow to create node translation</p>');
}
return $output;
}
/**
* Implementation of hook_menu().
*/
function translation_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'admin/node/translation',
'title' => t('translation'),
'callback' => 'translation_node_admin',
'access' => user_access('administer nodes'),
if (arg(0) == 'node' && is_numeric(arg(1)) && variable_get('i18n_node_'.translation_get_node_type(arg(1)), 0)) {
$access = user_access('translate nodes');
$type = MENU_LOCAL_TASK;
$items[] = array(
'path' => 'node/'. arg(1) .'/translation',
'title' => t('translation'),
'callback' => 'translation_node_page',
'access' => $access,
'type' => $type,
'weight' => 3);
}
if(arg(0) == 'admin' && arg(1) == 'taxonomy' && is_numeric(arg(2)) ) {
$items[] = array(
'path' => 'admin/taxonomy/'.arg(2).'/translation',
'title' => t('translation'),
'callback' => 'translation_taxonomy_admin',
'access' => user_access('administer taxonomy'),
'type' => MENU_LOCAL_TASK);
}
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
}
return $items;
}
/**
* Implementation of hook_perm
*/
function translation_perm(){
return array('translate nodes');
}
/**
* Implementation of hook_settings
*/
function translation_settings(){
$form['i18n_translation_links'] = array(
'#type' => 'radios',
'#title' => t('Language Management'),
'#default_value' => variable_get('i18n_translation_links', 0),
'#options' => array(t('Interface language depends on content.'), t('Interface language is independent')),
'#description' => t("How interface language and content language are managed."),
);
$form['i18n_translation_node_links'] = array(
'#type' => 'radios',
'#title' => t('Links to node translations'),
'#default_value' => variable_get('i18n_translation_node_links', 0),
'#options' => array(t('None.'), t('Main page only'), t('Teaser and Main page')),
'#description' => t("How interface language and content language are managed."),
);
return $form;
}
/**
* Translation block
*
* This is a simple language switcher which knows nothing about translations
*/
function translation_block($op = 'list', $delta = 0) {
if ($op == 'list') {
$blocks[0]['info'] = t('Translations');
}
elseif($op == 'view') {
$blocks['subject'] = t('Languages');
$blocks['content'] = theme('item_list', translation_get_links($_GET['q']));
}
return $blocks;
}
/**
* Implementation of hook_form_alter
*/
function translation_form_alter($form_id, &$form) {
//drupal_set_message("translation_form_alter form_id=$form_id ");
// Node edit form
if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id && variable_get('i18n_node_'.$form['type']['#value'], 0)){
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
$node = $form['#node'];
$languages = i18n_supported_languages();
if ($node->nid && $node->translation) {
$translations = $node->translation;
}
elseif (arg(3) == 'translation' && user_access('translate nodes')) {
// We are translating a node: node/add/type/translation/nid/lang
$translation_nid = arg(4);
$language = arg(5);
// Load the node to be translated and populate fields
$trans = node_load($translation_nid);
translation_node_populate_fields($trans, $form, $node);
$form['i18n']['translation_nid'] = array('#type' => 'hidden', '#value' => $translation_nid);
$form['i18n']['language']['#default_value'] = $language;
if($trans->trid){
$form['i18n']['trid'] = array('#type' => 'hidden', '#value' => $trans->trid);
}
//print "<pre>"; var_dump($form); print "</pre>";
$translations = $trans->translation;
$translations[$trans->language] = $trans;
}
//$form .= form_select(t('Language'), 'language', $node->language ? $node->language : i18n_get_lang(), $langselect, t('If you change the Language, you must click on <i>Preview</i> to get the right Categories & Terms for that language.'));
if ($translations) {
// Unset invalid languages
foreach(array_keys($translations) as $lang) {
unset($form['i18n']['language']['#options'][$lang]);
}
// Add translation list
$form['i18n']['#title'] = t('Language and translations');
$form['i18n']['translations'] = array(
'#type' => 'markup',
'#value' => theme('translation_node_list', $translations, FALSE)
);
}
function translation_node_populate_fields($source, &$form, &$node){
foreach(element_children($form) as $key) {
if($key != 'nid' && $key != 'vid' && isset($source->$key) && !isset($node->$key)) {
$node->$key = $form[$key]['#default_value'] = $source->$key;
drupal_set_message("populated $key");
} elseif(!isset($form[$key]['#tree'])) {
translation_node_populate_fields($source, $form[$key], $node);
}
}
}
/**
* Multilingual Nodes support
*/
/**
* This is the callback for the tab 'translation' for nodes
*/
function translation_node_page() {
$args = func_get_args();
$op = isset($_POST['op']) ? $_POST['op'] : $args[0];
$edit = $_POST['edit'];
$nid = arg(1);
$node = node_load($nid);
drupal_set_title($node->title);
$output = '';
switch($op){
case 'select':
$output .= translation_node_overview($node);
$output .= translation_node_form($node, $args[1]);
case t('Save'):
$output .= translation_node_form($node, $args[1]);
case 'remove':
case t('Remove'):
db_query("UPDATE {i18n_node} SET trid = NULL WHERE nid=%d", $node->nid);
drupal_set_message("The node has been removed from the translation set");
drupal_goto("node/$node->nid/translation");
$output .= translation_node_overview($node);
}
print theme('page', $output);
function translation_node_overview($node) {
$languages = i18n_supported_languages();
unset($languages[$node->language]);
$output = t('<h2>Current translations</h2>');
$header = array(t('Language'), t('Title'), t('Options'));
foreach($languages as $lang => $langname){
$options = array();
if(isset($node->translation[$lang])){
$trnode = $node->translation[$lang];
$title = l($trnode->title, 'node/'.$trnode->nid);
} else {
$title = t('Not translated');
$options[] = l(t('create translation'), "node/add/$node->type/translation/$node->nid/$lang");
}
$options[] = l(t('select node'), "node/$node->nid/translation/select/$lang");
$rows[] = array($langname, $title, implode(" | ", $options));
}
$output .= theme('table', $header, $rows);
if($node->trid){
$form['submit'] = array('#type' => 'submit', '#value' => t('Remove'), '#suffix' => t('Remove node from this translation set'));
$output .= drupal_get_form(NULL, $form);
}
return $output;
function translation_node_form($node, $lang){
$form['node'] = array('#type' => 'value', '#value' =>$node);
$form['language'] = array('#type' => 'hidden', '#value' => $lang);
$form['source_nid'] = array('#type' => 'hidden', '#value' => $node->nid);
$form['trid'] = array('#type' => 'hidden', '#value' => $node->trid);
$languages = i18n_supported_languages();
// Disable i18n rewrite. Order by trid to show first nodes with no translation
i18n_selection_mode('off');
$result = pager_query(db_rewrite_sql("SELECT n.nid, n.title FROM {node} n INNER JOIN {i18n_node} i ON n.nid = i.nid WHERE i.language = '%s' ORDER BY i.trid"), 40, 0, NULL, $lang);
i18n_selection_mode('user');
while($trnode = db_fetch_object($result)){
$list[$trnode->nid] = l($trnode->title, "node/$trnode->nid") ;
}
if($list){
$form['nodes']['nid'] = array(
'#type' => 'radios', '#title' => t('Select translation for %language', array('%language' => $languages[$lang])),
'#default_value' => isset($node->translation[$lang]) ? $node->translation[$lang]->nid : '',
'#options' => $list);
$form['pager'] = array('#value' => theme('pager'));
$form['submit'] = array('#type' => 'submit', '#value' => t('Save'));
return drupal_get_form('translation_node_form', $form);
} else {
return t("<p>No nodes available in %language</p>", array('%language' => $languages[$lang]) );
function translation_node_form_submit($form_id, $form_values){
$op = $_POST['op'];
$source_nid = $form_values['source_nid'];
$language = $form_values['language'];
$nid = $form_values['nid'];
if( $source_nid && $language && $nid ) {
if($trid = $form_values['trid']){
// Delete old translations
db_query("UPDATE {i18n_node} SET trid = 0 WHERE trid = %d AND language = '%s'", $trid, $language);
} else {
$trid = db_next_id('{i18n_node}_trid');
db_query("UPDATE {i18n_node} SET trid = %d WHERE nid=%d OR nid=%d", $trid, $source_nid, $nid);
drupal_set_message(t('The translation has been saved'));
}
}
/**
* Hook nodeapi
*
* Delete case is now handled in i18n_nodeapi
*/
function translation_nodeapi(&$node, $op, $arg = 0) {
if (variable_get("i18n_node_$node->type", 0)) {
switch ($op) {
case 'load':
$node->translation = translation_node_get_translations(array('nid' =>$node->nid), FALSE);
break;
if($node->translation_nid && !$node->trid){
// Update both nodes
$node->trid = db_next_id('{i18n_node}_trid');
db_query("UPDATE {i18n_node} SET trid = %d WHERE nid=%d OR nid=%d", $node->trid, $node->nid, $node->translation_nid);
}
break;
}
}
}
/**
* Taxonomy hook
* $edit parameter is an array, not an object !!
*/
// $op = insert, update, delete
function translation_taxonomy($op, $type, $edit = NULL) {
switch ("$type/$op") {
case 'term/insert':
case 'term/update':
if (!$edit['language'] && $edit['trid']) {
// Removed language, remove trid
db_query('UPDATE {term_data} SET trid=0 WHERE tid=%d', $edit['tid']);
if(db_affected_rows()) drupal_set_message(t('Removed translation information from term'));
}
break;
}
}
/**
* Implementation of hook_link().
*/
function translation_link($type, $node = NULL, $teaser = FALSE) {
$languages = i18n_supported_languages();
if ($type == 'node' && variable_get('i18n_translation_node_links', 0) > ($teaser ? 1 : 0) && $node->translation) {
foreach ($node->translation as $lang => $trnode) {
$baselang = variable_get('i18n_translation_links', 0) ? i18n_get_lang() : $lang;
$links[]= theme('translation_node_link', $trnode , $lang, $baselang);
}
}
return $links;
}
/**
* Returns a list for terms for vocabulary, language
function translation_vocabulary_get_terms($vid, $lang, $status = 'all') {
switch($status){
case 'translated':
$andsql = ' AND trid > 0';
break;
case 'untranslated':
$andsql = ' AND trid = 0';
break;
default:
$andsql = '';
$result = db_query("SELECT * FROM {term_data} WHERE vid=%d AND language='%s' $andsql", $vid, $lang);
while ($term = db_fetch_object($result)) {
$list[$term->tid] = $term->name;
}
return $list;
}
/**
* Get translations
* @param $params = array of parameters
* @param $getall = TRUE to get the also node itself
function translation_node_get_translations($params, $getall = TRUE) {
foreach($params as $field => $value) {
$conds[] = "b.$field = '%s'";
$values[] = $value;
if(!$getall){ // If not all, a parameter must be nid
$conds[] = "n.nid != %d";
$values[] = $params['nid'];
$sql = 'SELECT n.nid, n.title, n.status, a.language FROM {node} n INNER JOIN {i18n_node} a ON n.nid = a.nid INNER JOIN {i18n_node} b ON a.trid = b.trid WHERE '. implode(' AND ', $conds);
i18n_selection_mode('off');
$result = db_query(db_rewrite_sql($sql), $values);
i18n_selection_mode('user');
$items = array();
while ($node = db_fetch_object($result)) {
$items[$node->language] = $node;
}
return $items;
}
function translation_get_node_type($nid) {
return db_result(db_query('SELECT type FROM {node} WHERE nid=%d', $nid));
}
/**
* Multilingual Taxonomy
*
*/
/**
* This is the callback for taxonomy translations
*
* Gets the urls:
* admin/taxonomy/i18n/term/xx
* admin/taxonomy/i18n/term/new/xx
* admin/taxonomy/vid/translation/op/trid
function translation_taxonomy_admin() {
$vid = arg(2);
$op = $_POST['op'] ? $_POST['op'] : arg(4);
$edit = $_POST['edit'];
case t('Save'):
case 'edit':
drupal_set_title(t('Edit term translations'));
$output = translation_taxonomy_form($vid, arg(5), $edit);
drupal_set_title(t('Submit'));
translation_taxonomy_term_save($edit);
$output = translation_taxonomy_overview($vid);
//print theme('page', node_delete($edit), t('Delete'));
break;
default:
$output = translation_taxonomy_overview($vid);
}
return $output;
}
/**
* Generate a tabular listing of translations for vocabularies.
*/
function translation_taxonomy_overview($vid) {
$vocabulary = taxonomy_get_vocabulary($vid);
drupal_set_title(check_plain($vocabulary->name));
$languages = i18n_supported_languages();
$header = array_merge($languages, array(t('Operations')));
$links = array();
$types = array();
// Get terms/translations for this vocab
$result = db_query('SELECT * FROM {term_data} t WHERE vid=%d',$vocabulary->vid);
while ($term = db_fetch_object($result)) {
if($term->trid && $term->language) {
$terms[$term->trid][$term->language] = $term;
}
}
// Reorder data for rows and languages
foreach ($terms as $trid => $terms) {
$thisrow = array();
foreach ($languages as $lang => $name) {
if (array_key_exists($lang, $terms)) {
$thisrow[] = $terms[$lang]->name;
}
else {
$thisrow[] = '--';
}
$thisrow[] = l(t('edit'), "admin/taxonomy/$vid/translation/edit/$trid");
$rows[] = $thisrow;
$output .= theme('table', $header, $rows);
$output .= l(t('new translation'), "admin/taxonomy/$vid/translation/edit/new");
return $output;
function translation_taxonomy_form($vid, $trid = NULL, $edit = array()) {
$languages = i18n_supported_languages();
if ($trid == 'new') {
$translations = array();
} else {
$form['trid'] = array('#type' => 'hidden', '#value' => $trid);
$translations = translation_term_get_translations(array('trid' =>$trid));
$vocabulary = taxonomy_get_vocabulary($vid);
// List of terms for languages
foreach ($languages as $lang => $langname) {
$current = isset($translations[$lang]) ? $translations[$lang]->tid : '';
$list = translation_vocabulary_get_terms($vid, $lang, 'all');
$list[''] = '--';
$form[$lang] = array('#type' => 'fieldset', '#tree' => TRUE);
$form[$lang]['tid'] = array(
'#type' => 'select',
'#title' => $langname,
'#default_value' => $current,
'#options' => $list
);
$form[$lang]['old'] = array('#type' => 'hidden', '#value' =>$current);
}
$form['submit'] = array('#type' => 'submit', '#value' => t('Save'));
return drupal_get_form('translation_taxonomy', $form);
function translation_taxonomy_submit($form_id, $form_values) {
$trid = $form_values['trid'];
$languages = i18n_supported_languages();
$translations = array();
// Delete old translations
if($trid){
db_query("UPDATE {term_data} SET trid = 0 WHERE trid=%d", $trid);
}
foreach ($languages as $lang => $name) {
if (is_numeric($form_values[$lang]['tid'])) {
$translations[$lang] = $form_values[$lang]['tid'];
}
}
if(count($translations)) {
$trid = is_numeric($trid) ? $trid : db_next_id('{term_data}_trid');
db_query('UPDATE {term_data} SET trid=%d WHERE tid IN(%s)', $trid, implode(',',$translations));
}
drupal_set_message(t('Term translations have been updated'));
}
/**
* Converts a list of arrays to an array of the form keyfield => namefield
*/
function translation_array2list($data, $keyfield, $namefield = 'name') {
foreach ($data as $key => $value) {
if (is_array($data)) {
$list[$value[$keyfield]] = $value[$namefield];
}
else {
$list[$value->$keyfield] = $value->$namefield;
}
}
return $list;
}
// returns array lang > term
function translation_term_get_translations($params, $getall = TRUE) {
foreach($params as $field => $value) {
$conds[] = "i.$field = '%s'";
$values[] = $value;
}
if(!$getall){ // If not all, a parameter must be tid
$conds[] = "t.tid != %d";
$values[] = $params['tid'];
}
$sql = 'SELECT t.* FROM {term_data} t INNER JOIN {term_data} i ON t.trid = i.trid WHERE '. implode(' AND ', $conds);;
$result = db_query($sql, $values);
$items = array();
while ($data = db_fetch_object($result)) {
$items[$data->language] = $data;
}
function translation_url($url, $lang) {
global $i18n_langpath;
// If !url get from original request
if (!$url) {
$url = _i18n_get_original_path();
}
// If url has lang_prefix, remove it
i18n_get_lang_prefix($url, true);
// are we looking at a node?
if (preg_match("/^(node\/)([0-9]*)$/",$url,$matches)) {
if ($nid = translation_node_nid($matches[2], $lang)) {
$url = "node/$nid";
}
}
// or a taxonomy term
elseif (preg_match("/^(taxonomy\/term\/)([^\/]*)$/",$url,$matches)) {//or at a taxonomy-listing?
if ($str_tids = translation_taxonomy_tids($matches[2], $lang)) {
$url = "taxonomy/term/$str_tids";
}
}
return $url;
}
/**
* Returns an url-part, pointing to the translated node, if exists
*/
function translation_node_nid($nid, $lang) {
$sql = 'SELECT n.nid FROM {i18n_node} n INNER JOIN {i18n_node} a ON n.nid = a.nid INNER JOIN {i18n_node} b ON a.trid = b.trid AND b.nid =%d WHERE n.nid != %d AND n.language = \'%s\'';
return db_result(db_query($sql, $nid, $nid, $lang));
}
/**
* Returns an url for the translated taxonomy-page, if exists
*/
function translation_taxonomy_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);
}
else if (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 = translation_term_get_translations(array('tid' =>$tid))) {
$translated_tids[] = $translated_tid[$lang]->tid;
}
}
return implode($separator, $translated_tids);
}
* function translation_get_links
* Returns an array of links for all languages, with or without names
*/
function translation_get_links($path = '', $names = 1) {
$current = i18n_get_lang();
foreach(i18n_supported_languages() as $lang => $name){
$url = translation_url($path, $lang);
$name = $names ? $name: '' ; // Should be localized??
$links[]= theme('i18n_link', $name, "$lang/$url" , $lang);
}
return $links;
}
/**
* Themeable functions
*/
function theme_translation_node_link($node, $lang, $baselang = NULL, $title = FALSE){
$baselang = $baselang ? $baselang : $lang;
if($title){
$name = $node->title;
} else {
$languages = i18n_supported_languages();
$name = $languages[$lang];
}
return theme('i18n_link', $name, "$baselang/node/$node->nid", $lang);
}
function theme_translation_link($text, $target, $lang, $separator=' ') {
return theme('i18n_link', $text, $target, $lang, $separator);
}
function theme_translation_node_list($list){
$header = array(t('Language'), t('Title'));
$languages = i18n_supported_languages();
foreach($list as $lang => $node){
$rows[] = array($languages[$lang], l($node->title, 'node/'.$node->nid) );
}
return theme('table', $header, $rows);
}