Contributions API

Calling all Drupal developers!

Help us get this on the first page of Digg. DIGG NOW!

Modules in 6

i18n.module

<?php
// $Id: i18n.module,v 1.41.2.2 2008/04/01 16:10:32 jareyero Exp $

/**
 * @file
 * Internationalization (i18n) module
 *
 * This module extends multilingual support being the base module for the i18n package.
 * - Multilingual variables
 * - Extended languages for nodes
 * - Extended language API
 * 
 * @author Jose A. Reyero, 2004
 *
 */

// Some constants. Language support modes for content
define('LANGUAGE_SUPPORT_NONE', 0);
define('LANGUAGE_SUPPORT_NORMAL', 1);
define('LANGUAGE_SUPPORT_EXTENDED', 2);

/**
 * Implementation of hook_init()
 * 
 * Will initialize language dependent variables
 * Modify rewriting conditions when viewing specific nodes
 */
function i18n_init(){
  // If not in bootstrap, variable init
  if(!_i18n_is_bootstrap()){
    //include drupal_get_path('module', 'i18n').'/i18n.inc';
    i18n_variable_init();  
    // Initialize selection mode for content, the default may be changed below
    i18n_selection_mode(variable_get('i18n_selection_mode', 'simple'));
    // Node language when loading specific nodes or creating translations
    if (arg(0) == 'node') {
      if (is_numeric(arg(1)) && ($node = node_load(arg(1))) && $node->language ) {
        i18n_selection_mode('node', $node->language);
      } elseif (arg(1) == 'add' && !empty($_GET['translation']) && !empty($_GET['language']))  {
        i18n_selection_mode('translation', db_escape_string($_GET['language']));
      } 
    } elseif (arg(0) == 'admin') {
      // There are some exceptions for admin pages
      if (arg(1) == 'content' && user_access('administer all languages')) {
        // No restrictions for administration pages
        i18n_selection_mode('off');
      } elseif (arg(1) == 'build' && arg(2) == 'menu-customize') {
        // All nodes available when editing custom menu items
        i18n_selection_mode('off');
      }
    }
  }
}

/**
 * Implementation of hook_help().
 */
function i18n_help($section = 'admin/help#i18n' ) {
  switch ($section) {
    case 'admin/help#i18n' :
      $output = '<p>'.t('This module improves support for multilingual content in Drupal sites:').'</p>';
      $output .= '<ul>';
      $output .= '<li>'.t('Shows content depending on page language').'</li>';
      $output .= '<li>'.t('Handles multilingual variables').'</li>';
      $output .= '<li>'.t('Extended language option for chosen content types. For these content types transations will be allowed for all defined languages, not only for enabled ones.').'</li>';
      $output .= '<li>'.t('Provides a block for language selection and two theme functions: <i>i18n_flags</i> and <i>i18n_links</i>').'</li>';     
      $output .= '</ul>';
      $output .= '<p>'.t('This is the base module for several others adding different features:').'</p>';
      $output .= '<ul>';      
      $output .= '<li>'.t('Multilingual menu items').'</li>';       
      $output .= '<li>'.t('Multilingual taxonomy Adds a language field for taxonomy vocabularies and terms').'</li>';
      $output .= '</ul>';
      $output .= '<p>'. t('For more information please read the <a href="@i18n">on-line help pages</a>.', array('@i18n' =>'http://drupal.org/node/31631')) .'</p>';
      return $output;
    case 'admin/settings/i18n':
      $output = '<ul>';
      $output .= '<li>'.t('To manage languages go to the !configure_languages', array('!configure_languages' => l(t('Languages configuration page'), 'admin/settings/language'))).'</li>';
      $output .= '<li>'.t('To enable multilingual support for specific content types go to !configure_content_types.', array('!configure_content_types' => l(t('configure content types'), 'admin/content/types'), )).'</li>';
      $output . '</ul>';
      return $output;
  }
}

/**
 * Implementation of hook_menu().
 */
function i18n_menu() {
  $items['admin/settings/i18n'] = array(
    'title' => 'Multilingual system',
    'description' => 'Configure extended options for multilingual content and translations.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('i18n_admin_settings'),
    'access arguments' => array('administer site configuration'),
    'file' => 'i18n.admin.inc',
  );
  $items['admin/settings/i18n/main'] = array(
    'title' => 'Internationalization',
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );

  return $items;
}

/**
 * Implementation of hook_menu_alter().
 * 
 * Take over the node translation page
 */
function i18n_menu_alter(&$items) {
  // dsm($router_items);
  /*
  $items['node/%node/translate']['page callback'] = 'i18n_translation_node_overview';
  $items['node/%node/translate']['file'] = 'i18n.pages.inc';
  $items['node/%node/translate']['module'] = 'i18n';
  */
  /**
  $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,
    'file' => 'i18n.pages.inc',
  );
  return $items;
  */
}

/**
 * Implementation of hook_nodeapi().
 */
/*
function i18n_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
  if (variable_get("i18n_node_$node->type", 0)) {
      switch ($op) {
      case 'load':
        return db_fetch_array(db_query("SELECT trid, language, status AS i18n_status FROM {i18n_node} WHERE nid=%d", $node->nid));
      case 'insert':
      case 'update':
        db_query("DELETE FROM {i18n_node} WHERE nid=%d",$node->nid);
        if ($node->language){
          // Assign a trid from the beginning
          db_query("INSERT INTO {i18n_node} (nid, trid, language, status) VALUES(%d, '%d', '%s', '%d')", $node->nid, $node->trid, $node->language, $node->i18n_status);
        }
        // Handle menu items. Fixes duplication issue and language for menu items which happens when editing nodes in languages other than current.
        if (isset($node->menu) && !$node->menu['delete'] && $node->menu['title']) {
          $item = $node->menu;
          $item['path'] = ($item['path']) ? $item['path'] : "node/$node->nid";
          $item['type'] = $item['type'] | MENU_MODIFIED_BY_ADMIN;
          if ($item['mid']) {
            // Update menu item 
            db_query("UPDATE {menu} SET pid = %d, path = '%s', title = '%s', description = '%s', weight = %d, type = %d, language = '%s' WHERE mid = %d", $item['pid'], $item['path'], $item['title'], $item['description'], $item['weight'], $item['type'], $node->language, $item['mid']);
            drupal_set_message(t('The menu item %title has been updated with node language.', array('%title' => $item['title'])));
          } elseif(SAVED_NEW == menu_save_item($item)) {
            // Creating new menu item with node language
            db_query("UPDATE {menu} SET language = '%s' WHERE mid = %d", $node->language, $item['mid']);
            drupal_set_message(t('The menu item %title has been added with node language.',  array('%title' => $item['title'])));         
          }
          menu_rebuild();
          unset($node->menu); // Avoid further processing by menu module
        }
        // Pathauto integration. Dynamic replacement of variables to allow different patterns per language
        if (module_exists('path') && module_exists('pathauto')) {
          // Language for pathauto variables is either node language or default language
          $language = $node->language ? $node->language : i18n_default_language();
          if ($language != i18n_get_lang()) {
            i18n_variable_init($language, 'pathauto_node');
          }
        }
        break;
      case 'delete': 
        db_query('DELETE FROM {i18n_node} WHERE nid=%d', $node->nid);
        break;
      case 'prepare':
        // Book pages, set the right language nodes and outlines
        if (arg(3) == 'parent' && is_numeric(arg(4)) && ($parent = node_load(arg(4))) && $parent->language) {
          $node->language = $parent->language;
          i18n_selection_mode('node', $parent->language);
        } 
        break;
      }
  }   
}
*/

/**
 * Implementation of hook_alter_translation_link().
 *
 * Handles links for extended language. The links will have current language
 */
function i18n_translation_link_alter(&$links, $path) {
  global $language;
  
  // Check for a node related path, and for its translations.
  if ((preg_match("!^node/([0-9]+)(/.+|)$!", $path, $matches)) && ($node = node_load((int)$matches[1])) && !empty($node->tnid)) {
    $languages = language_list();
    $extended = array();
    foreach (translation_node_get_translations($node->tnid) as $langcode => $translation_node) {
      if (!isset($links[$langcode]) && isset($languages[$langcode])) {
        $extended[$langcode] = array(
           'href' => 'node/'.$translation_node->nid . $matches[2],
           'language' => $language,
           'language_icon' => $languages[$langcode],
           'title' => $languages[$langcode]->native,
           'attributes' => array('class' => 'language-link'),
        );
      }
    }
    // This will run after languageicon module, so we add icon in case that one is enabled
    if ($extended && function_exists('languageicons_translation_link_alter')) {
      languageicons_translation_link_alter($extended, $path);
    }
    $links = array_merge($links, $extended);
  }
}

/**
 * Implementation of hook_link_alter().
 *
 * Handles links for extended languages. Sets current interface language;
 */
function i18n_link_alter(&$links, $node) {
  global $language;
  
  if ($node->tnid) {
    foreach (array_keys(i18n_language_list('extended')) as $langcode) {
      $index = 'node_translation_'.$langcode;
      if (!empty($links[$index])) {
        $links[$index]['language'] = $language;
      }
    }
  }
}

/**
 * Implementation of hook_user()
 * 
 * Switch to user's language after login
 */
function i18n_user($op, &$edit, &$account, $category = NULL) {
  if($op == 'login' && $account->language) {
    $_SESSION['language'] = $account->language;
    i18n_get_lang($account->language);
  }
}

/**
 * Simple i18n API
 */

/**
 * Get language properties
 * 
 * @param $code
 *   Language code
 * @param $property
 *   It may be 'name', 'native', 'ltr'...
 */
function i18n_language_property($code, $property) {
  $languages = language_list();
  return isset($languages[$code][$property]) ? $languages[$code][$property] : NULL;
}

/**
 * Get node language
 */
function i18n_node_get_lang($nid, $default = '') {
  $lang = db_result(db_query('SELECT language FROM {node} WHERE nid = %d',$nid));
  return $lang ? $lang : $default ;
}

/**
 * Get allowed languages for node
 * 
 * This allows node types to define its own language list implementing hook 'language_list'
 * 
 * @param $node
 *   Node to retrieve language list for
 * @param $translate
 *   Only languages available for translation. Filter out existing translations
 */
function i18n_node_language_list($node, $translate = FALSE) {
  // Check if the node module manages its own language list
  $languages = node_invoke($node, 'language_list', $translate);
  if (!$languages) {
    if (variable_get('i18n_node_'.$node->type, 0) == LANGUAGE_SUPPORT_EXTENDED) {
      $languages = locale_language_list('name', TRUE); // All defined languages
    } else {
      $languages = locale_language_list(); // All enabled languages
    }
    if ($translate && isset($node->tnid) && $node->tnid && ($translations = translation_node_get_translations($node->tnid))) {
      unset($translations[$node->language]);
      foreach (array_keys($translations) as $langcode) {
        unset($languages[$langcode]);
      }
    }
    $languages = array('' => t('Language neutral')) + $languages;
  }

  return $languages;
}

/**
 * Function i18n_get_links
 * 
 * Returns an array of links for all languages, with or without names/flags
 * 
 * @param $path
 *   Drupal internal path
 * @param $query
 *   Query string
 * @param $names
 *   Names to use for the links. Defaults to native language names
 */
function i18n_get_links($path = '', $query = NULL, $names = NULL) {
  if($path == i18n_frontpage()) {
    $path = '';
  }
  $names = $names ? $names : locale_language_list('native');
  foreach (array_keys(i18n_supported_languages()) as $lang){
    $links[$lang]= theme('i18n_link', $names[$lang], i18n_path($path, $lang), $lang, $query);
  }
  return $links;  
}

/**
 * i18n_selection_mode
 * 
 * Allows several modes for query rewriting and to change them programatically
 * 	off = No language conditions inserted
 * 	simple = Only current language and no language
 * 	mixed = Only current and default languages
 *  strict = Only current language
 *  default = Only default language
 *  user = User defined, in the module's settings page
 *  params = Gets the stored params
 *  reset = Returns to previous
 *  custom = add custom where clause, like "%alias.language = 'en'"
 */
function i18n_selection_mode($mode= NULL, $params= NULL){
  static $current_mode = 'simple';
  static $current_value = '';
  static $store = array();
  
  if(!$mode) {
    return $current_mode;
  } elseif($mode == 'params'){
    return $current_value;
  } elseif($mode == 'reset'){
    list($current_mode, $current_value) = array_pop($store);
  } else {
    array_push($store, array($current_mode, $current_value));
    $current_mode = $mode;
    $current_value = $params;
  } 
}

/**
 * Implementation of hook_db_rewrite_sql()
 * 
 * Rewrite node queries so language selection options are enforced
 */
function i18n_db_rewrite_sql($query, $primary_table, $primary_key){
  // If mode is 'off' = no rewrite, we cannot return any empty 'where' string so check here
  $mode = i18n_selection_mode();
  if ($mode == 'off') return;
  
  switch ($primary_table) {
    case 'n':
    case 'node':
      // No rewrite for queries with subselect ? (views count queries)
      // @ TO DO Actually these queries look un-rewrittable, check with other developers
      if (preg_match("/FROM \(SELECT/", $query)) return;
      // No rewrite for translation module queries
      if (preg_match("/.*FROM {node} $primary_table WHERE.*$primary_table\.tnid/", $query)) return;
      // When loading specific nodes, language conditions shouldn't apply
      if (preg_match("/WHERE.*\s$primary_table.nid\s*=\s*(\d|%d)/", $query)) return;
      // If language conditions already there, get out
      if (preg_match("/i18n/", $query)) return;

      //$result['join'] = "LEFT JOIN {i18n_node} i18n ON $primary_table.nid = i18n.nid";
      $result['where'] = i18n_db_rewrite_where($primary_table, 'node', $mode);
      return $result;
  }
}

/**
 * Rewrites queries depending on rewriting mode
 */
function i18n_db_rewrite_where($alias, $type, $mode = NULL){
  if (!$mode) {
    // Some exceptions for query rewrites
    $mode = i18n_selection_mode();
  } 
  // Special case. Selection mode is 'strict' but this should be only for node queries
  if ($mode == 'strict' && $type != 'node') {
    $mode = 'simple';
  }   
  switch($mode){
    case 'off':
      return '';
    case 'simple':
      return "$alias.language ='".i18n_get_lang()."' OR $alias.language ='' OR $alias.language IS NULL" ;
    case 'mixed':
      return "$alias.language ='".i18n_get_lang()."' OR $alias.language ='".i18n_default_language()."' OR $alias.language ='' OR $alias.language IS NULL" ;
    case 'strict':
      return "$alias.language ='".i18n_get_lang()."'" ;
    case 'node':
    case 'translation':
      return "$alias.language ='".i18n_selection_mode('params')."' OR $alias.language ='' OR $alias.language IS NULL" ;
    case 'default':
      return "$alias.language ='".i18n_default_language()."' OR $alias.language ='' OR $alias.language IS NULL" ;
    case 'custom':
      return str_replace('%alias', $alias, i18n_selection_mode('params'));
  }  
}

/**
 * Implementation of hook_exit
 */
function i18n_exit(){
  _i18n_variable_exit();
}

/**
 * Implementation of hook_form_alter();
 * 
 * This is the place to add language fields to all forms
 */
function i18n_form_alter(&$form, $form_state, $form_id) {
  switch ($form_id){
     case 'node_type_form':
       // Add extended language support option to content type form.
       $form['workflow']['i18n_node'] = array(
          '#type' => 'radios',
          '#title' => t('Extended language support'),
          '#default_value' => variable_get('i18n_node_'. $form['#node_type']->type, LANGUAGE_SUPPORT_NORMAL),
          '#options' => _i18n_content_language_options(),
          '#description' => t('If enabled, all defined languages will be allowed for this content type in addition to only enabled ones. This is useful to have more languages for content than for the interface.')
       );

       break;

    default:
      // Extended language for node edit form
      if (isset($form['#id']) && $form['#id'] == 'node-form') {
        if (isset($form['#node']->type) && variable_get('language_content_type_'. $form['#node']->type, 0)) {
          $form['language']['#options'] = i18n_node_language_list($form['#node'], TRUE);
        }
      }
      /** @ TO DO Upgrade
      if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id && $node = $form['#node']) {
        // Language field
        if(variable_get('i18n_node_'.$form['type']['#value'], 0) && !isset($form['i18n']['language'])) {
          // Language field
          $form['i18n'] = array('#type' => 'fieldset', '#title' => t('Multilingual settings'), '#collapsible' => TRUE, '#collapsed' => FALSE, '#weight' => -4);
          // Language will default to current only when creating a node
          $language = isset($form['#node']->language) ? $form['#node']->language : (arg(1)=='add' ? i18n_get_lang() : '');
          $form['i18n']['language'] = _i18n_language_select($language, t('If you change the Language, you must click on <i>Preview</i> to get the right Categories &amp; Terms for that language.'), -4, i18n_node_language_list($node));
          $form['i18n']['trid'] = array('#type' => 'value', '#value' => $form['#node']->trid);
        }
        // Correction for lang/node/nid aliases generated by path module
        // if($form['#node']->path && $form['#node']->path == i18n_get_lang().'/node/'.$form['#node']->nid){
        if($node->path) {
          $alias = drupal_lookup_path('alias', 'node/'.$node->nid);
          if($alias && $alias != 'node/'.$node->nid){
            $form['#node']->path = $alias;
          } else {
            unset($form['#node']->path);
          }
        }
      }
      */
      // Multilingual variables in settings form
      if (isset($form['#theme']) && $form['#theme'] == 'system_settings_form' && $variables = variable_get('i18n_variables', 0)) {
        if (i18n_form_alter_settings($form, $variables)) {
          $form['#submit'][] = 'i18n_variable_form_submit';
        }
      }
  }    
}

/**
 * Implementation of hook_perm().
 * 
 * Permissions defined
 * - administer all languages
 *   Disables language conditions for administration pages, so the user can view objects for all languages at the same time.
 *   This applies for: menu items, taxonomy
 */
function i18n_perm() {
  return array('administer all languages');
}
/**
 * Process menu and menu item add/edit form submissions.
 */
function i18n_menu_edit_item_form_submit($form_id, $form_values) {
  $mid = menu_edit_item_save($form_values);
  db_query("UPDATE {menu} SET language = '%s' WHERE mid = %d", $form_values['language'], $mid);
  return 'admin/build/menu';
}

/**
 * Check for multilingual variables in form
 */
function i18n_form_alter_settings(&$form, &$variables) {
  $result = 0;
  foreach (element_children($form) as $field) {
    if(isset($form[$field]['#type']) && $form[$field]['#type'] == 'fieldset') {
      $result += i18n_form_alter_settings($form[$field], $variables);
    }
    elseif (in_array($field, $variables)) {
      $form[$field]['#description'] .= ' <strong>'.t('This is a multilingual variable.').'</strong>';
      $result++;
    }
  }
  return $result;
}

/**
 * Save multilingual variables and remove them from form
 */
function i18n_variable_form_submit($form, &$form_state) {
  $form_values = $form_state['values'];
  $op = isset($form_values['op']) ? $form_values['op'] : '';
  $variables = variable_get('i18n_variables', array());
  $language = i18n_get_lang();
  foreach ($form_values as $key => $value) {
    if (in_array($key, $variables)) {
      if ($op == t('Reset to defaults')) {
        i18n_variable_del($key, $language);
      }
      else {
        if (is_array($value) && isset($form_values['array_filter'])) {
          $value = array_keys(array_filter($value));
        }
        i18n_variable_set($key, $value, $language);
      }
      unset($form_values[$key]);
    } 
  }
  // Re-submit form
  // system_settings_form_submit($form_id, $form_values);
}

/**
 * Initialization of multilingual variables
 * 
 * @param $language
 *   Language to retrieve variables. Defaults to current language
 * @param $prefix
 *   Variable name prefix to load just a selected group of variables
 */
function i18n_variable_init($language = NULL, $prefix = ''){
  global $conf;
  global $i18n_conf;
  $language = $language ? $language : i18n_get_lang();
  if ($i18n_variables = variable_get('i18n_variables', '')){
    if (!$i18n_conf) {
      $i18n_conf = array();
    }
    $variables = _i18n_variable_init($language, $prefix);
    foreach($i18n_variables as $name){
      $i18n_conf[$name] = isset($variables[$name]) ? $variables[$name] : (isset($conf[$name]) ? $conf[$name] : '');
    }
    $conf = array_merge($conf, $i18n_conf);
  }
}



/**
 * Helper function to create language selector
 */
function _i18n_language_select($value ='', $description ='', $weight = -20, $languages = NULL){
  $languages = $languages ? $languages : locale_language_list();
  return array(
      '#type' => 'select',
      '#title' => t('Language'),
      '#default_value' => $value,
      '#options' => array_merge(array('' => ''), $languages),
      '#description' => $description,
      '#weight' => $weight,
  );
}

/**
 * Load language variables into array
 */
function _i18n_variable_init($language, $prefix = ''){  
  $variables = array();
  $cacheid = 'variables:'.$language.($prefix ? ':'.$prefix : '');
  if ($cached = cache_get($cacheid)) {
    $variables = $cached->data;
  }
  else {
    $result = db_query("SELECT * FROM {i18n_variable} WHERE language='%s' AND name LIKE '%s%'", $language, $prefix);
    while ($variable = db_fetch_object($result)) {
      $variables[$variable->name] = unserialize($variable->value);
    }
    cache_set($cacheid, $variables);
  }
  return $variables;
}

/**
 * Save multilingual variables that may have been changed by other methods than settings pages
 */
function _i18n_variable_exit(){
  global $i18n_conf;
  global $conf;
  if($i18n_conf){
    $lang = i18n_get_lang();
    $refresh = FALSE;
    // Rewritten because array_diff_assoc may fail with array variables
    foreach($i18n_conf as $name => $value){
      if($value != $conf[$name]) {
        $refresh = TRUE;
        $i18n_conf[$name] = $conf[$name];
        db_query("DELETE FROM {i18n_variable} WHERE name='%s' AND language='%s'", $name, $lang );
        db_query("INSERT INTO {i18n_variable} (language, name, value) VALUES('%s', '%s', '%s')", $lang, $name, serialize($conf[$name]));
      }
    }
    if($refresh) {
      cache_set('variables:'.$lang, 'cache', serialize($i18n_conf));
    }
  }
}

/**
 * Check whether we are in bootstrap mode
 */  
function _i18n_is_bootstrap(){
  return !function_exists('drupal_get_headers');
}    

/**
 * Drupal 6, backwards compatibility layer
 * @ TO DO Fully upgrade all the modules and remove
 */

/**
 * This one expects to be called first from common.inc
 */
function i18n_get_lang() {
  global $language;
  return $language->language;
}



/**
 * Language dependent front page
 * This function will search for aliases like 'en/home', 'es/home'...
 */
function i18n_frontpage($lang = NULL) {
  $lang = $lang ? $lang : i18n_get_lang();
  return i18n_get_normal_path($lang.'/'.variable_get('site_frontpage','node'));
}

/**
 * Implementation of hook_views_pre_query().
 * 
 * Disable language conditions for views. This is called before filter handlers
 * 
 * @ TODO Check whether these views hooks still exist in Drupal 6
 */
function i18n_pre_query(&$view) {
  i18n_selection_mode(variable_get('i18n_selection_mode', 'off'));
}

/**
 * Implementation of hook_views_pre_view().
 * 
 * If used language selection filter, reset query rewriting again
 */
function i18n_pre_view(&$view, &$items) {
  i18n_selection_mode('reset');
}

/**
 * @defgroup i18n_api Extended language API
 * @{
 * This is an extended language API to be used by modules in i18n package.
 */

/**
 * Returns language lists
 */
function i18n_language_list($type = 'enabled', $field = 'name') {
  switch ($type) {
    case 'enabled':
      return locale_language_list($field);
    case 'extended':
      $enabled = locale_language_list($field);
      $defined = locale_language_list($field, TRUE);
      return array_diff_assoc($defined, $enabled);
  }
}

/**
 * Returns default language code
 */
function i18n_default_language(){
  return language_default('language'); 
}

/**
 * Get list of supported languages, native name
 * 
 * @param $all
 *   TRUE to get all defined languages
 */
function i18n_supported_languages($all = FALSE) {
  return locale_language_list('native', $all);
}

/**
 * Set a persistent language dependent variable.
 *
 * @param $name
 *   The name of the variable to set.
 * @param $value
 *   The value to set. This can be any PHP data type; these functions take care
 *   of serialization as necessary.
 * @param $langcode
 *   Language code
 */
function i18n_variable_set($name, $value, $langcode) {
  global $conf, $i18n_conf;

  db_lock_table('i18n_variable');
  db_query("DELETE FROM {i18n_variable} WHERE name = '%s' AND language='%s'", $name, $langcode);
  db_query("INSERT INTO {i18n_variable} (name, language, value) VALUES ('%s', '%s', '%s')", $name, $langcode, serialize($value));
  db_unlock_tables();

  cache_clear_all('variables:'.$langcode, 'cache');

  $conf[$name] = $value;
  $i18n_conf[$name] = $value;
}

/**
 * Unset a persistent multilingual variable.
 *
 * @param $name
 *   The name of the variable to undefine.
 * @param $langcode
 *   Language code
 */
function i18n_variable_del($name, $langcode) {
  global $conf, $i18n_conf;

  db_query("DELETE FROM {i18n_variable} WHERE name = '%s' AND language='%s'", $name, $langcode);
  cache_clear_all('variables:'.$langcode, 'cache');

  unset($conf[$name]);
  unset($i18n_conf[$name]);
}

/**
 * Utility. Get part of array variable
 */
function i18n_array_variable_get($name, $element, $default = NULL) {
  if (($values = variable_get($name, array())) && isset($values[$element])) {
    return $values[$element];
  } else {
    return $default;
  }  
}

/**
 * Utility. Set part of array variable
 */
function i18n_array_variable_set($name, $element, $value) {
  $values = variable_get($name, array());
  $values[$element] = $value;
  variable_set($name, $values);
}

/**
 * @} End of "defgroup i18n_api".
 */

 // List of language support modes for content
function _i18n_content_language_options() {
  return array(
    LANGUAGE_SUPPORT_NORMAL => t('Normal - All enabled languages will be allowed.'),
    LANGUAGE_SUPPORT_EXTENDED => t('Extended - All defined languages will be allowed.')
  );
}