Using hook_language_types_info_alter I am attempting to modify the way the language negotiation is done on a site.

I've implemented a new language negotiation method:

/**
 * Implements hook_language_negotiation_info()
 */
function MODULE_language_negotiation_info() {
  return array(
    'MODULE_provider' =&gt; array(
      'file'        =&gt; drupal_get_path('module', 'MODULE') . '/MODULE.module',
      'weight'      =&gt; -4,
      'name'        =&gt; t('URL (Combined)'),
      'description' =&gt; t('Determine the language from the URL (Path prefix and domain).'),
      'cache'       =&gt; 0,
      'callbacks'   =&gt; array(
        'language'    =&gt; 'MODULE_language_provider_callback',
        'url_rewrite' =&gt; 'MODULE_language_url_rewrite_callback',
      ),
    ),
  );
}


In the case of a single language, the $language is being detected properly, the $language_content is being detected properly, but the $language_url is not being detected properly.

After some digging into this, I found that in the locale.module there are three language types defined - language, language_content and language_url:

/**
 * Implements hook_language_types_info().
 *
 * Defines the three core language types:
 * - Interface language is the only configurable language type in core. It is
 *   used by t() as the default language if none is specified.
 * - Content language is by default non-configurable and inherits the interface
 *   language negotiated value. It is used by the Field API to determine the
 *   display language for fields if no explicit value is specified.
 * - URL language is by default non-configurable and is determined through the
 *   URL language provider or the URL fallback provider if no language can be
 *   detected. It is used by l() as the default language if none is specified.
 */
function locale_language_types_info() {
  require_once DRUPAL_ROOT . '/includes/locale.inc';
  return array(
    LANGUAGE_TYPE_INTERFACE =&gt; array(
      'name' =&gt; t('User interface text'),
      'description' =&gt; t('Order of language detection methods for user interface text. If a translation of user interface text is available in the detected language, it will be displayed.'),
    ),
    LANGUAGE_TYPE_CONTENT =&gt; array(
      'name' =&gt; t('Content'),
      'description' =&gt; t('Order of language detection methods for content. If a version of content is available in the detected language, it will be displayed.'),
      'fixed' =&gt; array(LOCALE_LANGUAGE_NEGOTIATION_INTERFACE),
    ),
    LANGUAGE_TYPE_URL =&gt; array(
      'fixed' =&gt; array(LOCALE_LANGUAGE_NEGOTIATION_URL, LOCALE_LANGUAGE_NEGOTIATION_URL_FALLBACK),
    ),
  );
}


So, pressing onward, I implement hook_language_types_info_alter and add my callback function to the list of callbacks for the language_url language type:

function MODULE_language_types_info_alter(array &amp;$language_types) {
  $language_types[LANGUAGE_TYPE_URL]['fixed'][] = 'MODULE_language_provider_callback';
}


The issue I am facing is that the hook_language_types_info_alter is called after drupal_language_initialize, so all of the language types have already been determined before the hook alters the language types.

Also, all of these language types are stored as variables. I could in theory modify the variable, but I would rather do this the correct way using hooks.

How do I modify the language_url language type before drupal_language_initialize?
variables was definitely the key here. In my hook_language_types_info_alter hook, simply updating the variable with my callback did the trick:

/**
 * Implements hook_language_types_info_alter()
 */
function MODULE_language_types_info_alter(array &amp;$language_types) {
  $config = variable_get("language_negotiation_" . LANGUAGE_TYPE_URL);

  // put my callback first, since the first one to return a language wins.
  $newconfig['MODULE_provider']['callbacks']['language'] = 'MODULE_language_provider_callback';
  $newconfig['MODULE_provider']['file'] = drupal_get_path('module', 'MODULE') . '/MODULE.module';
  $newconfig += $config;

  variable_set("language_negotiation_" . LANGUAGE_TYPE_URL, $newconfig);
}