? translate_module.patch Index: modules/node/translation.info =================================================================== RCS file: modules/node/translation.info diff -N modules/node/translation.info --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/node/translation.info 8 May 2007 14:45:26 -0000 @@ -0,0 +1,6 @@ +; $Id: translation.info Exp $ +name = Content translation +description = Allows content to be translated into different languages. +dependencies[] = locale +package = Core - optional +version = VERSION Index: modules/node/translation.install =================================================================== RCS file: modules/node/translation.install diff -N modules/node/translation.install --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/node/translation.install 8 May 2007 14:45:26 -0000 @@ -0,0 +1,36 @@ +'. t('The translation module allows content translation for multilingual sites.') .'
'; + $output .= ''. t('For more information please read the configuration and customization handbook Translation page.', array('@translation' => 'http://drupal.org/handbook/modules/translation/')) .'
'; + return $output; + } +} + +/** + * Implementation of hook_menu(). + */ +function translation_menu() { + $items = array(); + $items['node/%node/translate'] = array( + 'title' => 'Translate', + 'page callback' => 'translation_node_overview', + 'page arguments' => array(1), + 'access callback' => '_translation_tab_access', + 'access arguments' => array(1), + 'type' => MENU_LOCAL_TASK, + 'weight' => 2, + ); + return $items; +} + +/** + * Menu access callback. + * + * Only display translation tab for node types, where language is enabled + * and where the current node is not language neutral (which should span + * all languages). + */ +function _translation_tab_access($node) { + if (!empty($node->language) && variable_get('language_' . $node->type, 0)) { + return user_access('translate content'); + } + return FALSE; +} + +/** + * Implementation of hook_perm(). + */ +function translation_perm() { + return array('translate content'); +} + +/** + * Implementation of hook_form_alter(). + * + * Alters language fields on node forms when a translation is about to be created. + */ +function translation_form_alter(&$form, $form_id) { + if ($form['#id'] == 'node-form' && variable_get('language_' . $form['#node']->type, 0)) { + $node = $form['#node']; + if (!empty($node->translation_source)) { + // We are creating a translation. Add values and lock language field. + $form['translation_source'] = array('#type' => 'value', '#value' => $node->translation_source); + $form['language']['#disabled'] = TRUE; + } + elseif (!empty($node->nid) && !empty($node->translation)) { + // Disable languages for existing translations, so it is not possible to switch this node + // to some language which is already in the translation set. + foreach (translation_node_get_translations($node) as $translation) { + unset($form['language']['#options'][$translation->language]); + } + } + } +} + +/** + * Implementation of hook_link(). + * + * Display translation links if this node is part of a translation set. + */ +function translation_link($type, $node = NULL, $teaser = FALSE) { + $links = array(); + if ($type == 'node' && !empty($node->translation) && $translations = translation_node_get_translations($node)) { + // Do not show link to the same node. + unset($translations[$node->language]); + foreach ($translations as $language => $translation) { + $links["node_translation_$language"] = array( + 'title' => locale_language_name($language), + 'href' => "node/$translation->nid", + 'attributes' => array('title' => $translation->title) + ); + } + } + return $links; +} + +/** + * Overview page for a node's translations. + * + * @param $node + * Node object. + */ +function translation_node_overview($node) { + $translations = translation_node_get_translations($node); + + $output = '' . t('%title is in @language, so it is possible to translate it to the following languages enabled on your site:', array('%title' => $node->title, '@language' => locale_language_name($node->language))) . '
'; + + $header = array(t('Language'), t('Title'), t('Status'), t('Operations')); + + $languages = language_list(); + unset($languages[$node->language]); + foreach ($languages as $language) { + $options = array(); + if (isset($translations[$language->language])) { + // We load the full node to check whether the user can edit it. + $trnode = node_load($translations[$language->language]->nid); + $title = l($trnode->title, 'node/'. $trnode->nid); + if (node_access('update', $trnode)) { + $options[] = l(t('edit'), "node/$trnode->nid/edit"); + } + $status = $trnode->status ? t('Published') : t('Not published'); + // If current node is source, add marker for older versions. + $status .= ($node->nid == $node->translation['trid'] && $node->vid > $trnode->vid ? ' '. t('outdated') .'' : ''); + } else { + $title = t('n/a'); + if (node_access('create', $node)) { + $options[] = l(t('add translation'), 'node/add/'. $node->type, array('query' => "translation=$node->nid&language=$language->language")); + } + $status = t('Not translated'); + } + $rows[] = array($language->name, $title, $status, implode(" | ", $options)); + } + $output .= theme('table', $header, $rows); + + drupal_set_title(t('Translations of %title', array('%title' => $node->title))); + return $output; +} + +/** + * Get translations for a specific node id. + * + * @param $param + * Either a node object or the 'trid' of the translation set. + * @return + * Array of node translations indexed by language. + */ +function translation_node_get_translations($param) { + $trid = (is_object($param) && !empty($param->translation['trid']) ? $param->translation['trid'] : $param); + $translations = array(); + if (is_numeric($trid) && $trid) { + $result = db_query('SELECT n.* FROM {node} n INNER JOIN {translation} t ON n.nid = t.nid WHERE t.trid = %d', $trid); + while ($node = db_fetch_object($result)) { + $translations[$node->language] = $node; + } + } + return $translations; +} + +/** + * Implementation of hook_nodeapi(). + * + * Manages translation information for nodes. + */ +function translation_nodeapi(&$node, $op, $teaser, $page) { + // Only if languages are enabled for this node type. + if (variable_get('language_' . $node->type, 0)) { + switch ($op) { + + case 'prepare': + if (empty($node->nid) && isset($_GET['translation']) && isset($_GET['language']) && ($source_nid = $_GET['translation']) && ($language = $_GET['language']) && (user_access('translate content'))) { + // We are translating a node from a source node, so + // load the node to be translated and populate fields. + $node->language = $language; + $node->translation_source = node_load($source_nid); + $node->title = $node->translation_source->title; + $node->body = $node->translation_source->body; + // Let every module add translated fields. + node_invoke_nodeapi($node, 'prepare translation'); + } + break; + + case 'load': + // Add a list of translation nids to the node. + return array('translation' => db_fetch_array(db_query('SELECT * FROM {translation} WHERE nid = %d', $node->nid))); + break; + + case 'insert': + if (!empty($node->translation_source)) { + if (empty($node->translation_source->translation['trid'])) { + // Create new translation set, using nid from the source node. + $trid = $node->translation_source->nid; + $svid = $node->translation_source->vid; + db_query("INSERT INTO {translation} (trid, nid, vid, svid) VALUES (%d, %d, %d, %d)", $trid, $node->translation_source->nid, $node->translation_source->vid, $svid); + } else { + // Add node to existing translation set. + $trid = $node->translation_source->translation['trid']; + $svid = $node->translation_source->translation['svid']; + } + db_query("INSERT INTO {translation} (trid, nid, vid, svid) VALUES (%d, %d, %d, %d)", $trid, $node->nid, $node->vid, $svid); + } + break; + + case 'update': + if (isset($node->translation) && $node->translation) { + if ($node->translation['nid']) { + // Update revision information in translation set. + db_query("UPDATE {translation} SET vid = %d, svid = %d WHERE nid = %d AND trid = %d", $node->vid, $node->translation['vid'], $node->translation['svid'], $node->nid, $node->translation['trid']); + } + else { + // The node may have been added to some existing translation set. + db_query("INSERT INTO {translation} (trid, nid, vid, svid) VALUES (%d, %d, %d, %d)", $node->translation['trid'], $node->nid, $node->vid, $node->translation['svid']); + } + } else { + // Remove node from translation set if existed. + db_query('DELETE FROM {translation} WHERE nid = %d', $node->nid); + } + break; + + case 'delete': + db_query('DELETE FROM {translation} WHERE nid = %d', $node->nid); + break; + } + } +} + +/** + * Return path of translations for a node, based on its path. + * + * @param $path + * A Drupal path + */ +function translation_path_get_translations($path) { + $output = array(); + // Check for a node related path, and for its translations. + if ((preg_match("/^(node\/)([0-9]+)(.*)$/", $path, $matches)) && ($node = node_load($matches[2])) && !empty($node->translation)) { + foreach (translation_node_get_translations($node) as $language => $trnode) { + $output[$language] = 'node/'.$trnode->nid.$matches[3]; + } + } + return $output; +}