diff --git a/geoip.module b/geoip.module
index 01790f3..93a7eb5 100644
--- a/geoip.module
+++ b/geoip.module
@@ -158,7 +158,7 @@ function _geoip_load_lib($file = 'geoip.inc') {
  * @return string
  *  Country Code
  */
-function geoip_country_code($ip = NULL) {
+function geoip_country_code($ip = NULL, $name = false) {
   $ip = $ip ? $ip : geoip_ip_address();
   $gi = geoip_instance();
 
@@ -166,7 +166,11 @@ function geoip_country_code($ip = NULL) {
     return FALSE;
   }
 
-  $cc = geoip_country_code_by_addr($gi, $ip);
+  if ($name) {
+    $cc = geoip_country_name_by_addr($gi, $ip);
+  } else {
+    $cc = geoip_country_code_by_addr($gi, $ip);
+  }
 
   geoip_close($gi);
 
diff --git a/geoip_language/geoip_language.admin.inc b/geoip_language/geoip_language.admin.inc
deleted file mode 100644
index 62052b9..0000000
--- a/geoip_language/geoip_language.admin.inc
+++ /dev/null
@@ -1,130 +0,0 @@
-<?php
-
-/**
- * @file
- * Admin page callbacks for the GeoIP Language module.
- */
-
-/**
- * Create the overview table of the already existing mappgins
- *
- * @param array $languages
- * @return string
- *  HTML Table
- */
-function geoip_language_settings_overview() {
-  if (variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE) != GEOIP_LANGUAGE_NEGOTIATION_PATH) {
-    drupal_set_message(t('The GeoIP settings will have no effect until <em>Language Negotiation</em> is set to <em>Path prefix with GeoIP detection fallback</em> on the <a href="@language-configure">Language configuration page</a>.', array('@language-configure' => url('admin/settings/language/configure'))), 'warning');
-  }
-
-  $countries = geoip_country_values();
-  $languages = locale_language_list('name', TRUE);
-  $mapping = geoip_language_mappings();
-
-  $rows = array();
-  foreach ($mapping as $country => $info) {
-    $rows[] = array(
-      $country,
-      $countries[$country],
-      $info->language,
-      $languages[$info->language],
-      l(t('Delete'), 'admin/settings/language/geoip/delete/'. $country, array('query' => drupal_get_destination())),
-    );
-  }
-  if (count($rows)) {
-    $header = array(
-      array('data' => t('Country'), 'colspan' => 2),
-      array('data' => t('Language'), 'colspan' => 2),
-      t('Operations'),
-    );
-    $output .= theme('table', $header, $rows);
-  }
-  else {
-    drupal_set_message(t('No GeoIP language mappings defined.'));
-  }
-
-  $output .= drupal_get_form('geoip_language_settings_form');
-  return $output;
-}
-
-/**
- * FAPI callback for creating a new country-language mapping.
- *
- * @return array
- */
-function geoip_language_settings_form() {
-  $countries = geoip_country_values();
-  $mapping = geoip_language_mappings();
-  $options = array();
-  foreach ($countries as $key => $value) {
-    if (!$mapping[$key]) {
-      $options[$key] = "$key - $value";
-    }
-  }
-
-  $form['new'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('New mapping'),
-    '#tree' => 0,
-  );
-  $form['new']['country'] = array(
-    '#type' => 'select',
-    '#title' => t('Detected country'),
-    '#options' => $options,
-  );
-  $form['new']['language'] = array(
-    '#type' => 'select',
-    '#title' => t('Language'),
-    '#options' => locale_language_list('name', TRUE),
-  );
-
-  $form['new']['buttons'] = array();
-  $form['new']['buttons']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Add mapping'),
-  );
-
-  return $form;
-}
-
-/**
- * FAPI submit handler.
- */
-function geoip_language_settings_form_submit($form, &$form_state) {
-  geoip_language_mapping_create($form_state['values']['country'], $form_state['values']['language']);
-
-  $countries = geoip_country_values();
-  drupal_set_message(t('GeoIP mapping created for %country.', array('%country' => $countries[$form_state['values']['country']])));
-
-  $form_state['redirect'] = 'admin/settings/language/geoip';
-}
-
-/**
- * Create the confirmmation form for deleting a mapping item.
- */
-function geoip_admin_delete_mapping(&$form_state, $country) {
-  $form['country'] = array(
-    '#type' => 'value',
-    '#value' => $country,
-  );
-
-  return confirm_form($form,
-    t('Are you sure you want to delete this mapping?'),
-    isset($_GET['destination']) ? $_GET['destination'] : 'admin/settings/language/geoip',
-    t('This action cannot be undone.'),
-    t('Delete'),
-    t('Cancel')
-  );
-}
-
-/**
- * Process a confirmed delete request of a mapping item.
- */
-function geoip_admin_delete_mapping_submit($form, &$form_state) {
-  geoip_language_mapping_delete($form_state['values']['country']);
-
-  $countries = geoip_country_values();
-  drupal_set_message(t('GeoIP mapping deleted for %country.', array('%country' => $countries[$form_state['values']['country']])));
-
-  $form_state['redirect'] = 'admin/settings/language/geoip';
-}
\ No newline at end of file
diff --git a/geoip_language/geoip_language.fastpath.inc b/geoip_language/geoip_language.fastpath.inc
deleted file mode 100644
index 5804f70..0000000
--- a/geoip_language/geoip_language.fastpath.inc
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-
-/**
- * @file
- * description
- */
-
-/**
- * Some sort of caching.
- */
-function page_cache_fastpath() {
-  $file = variable_get('file_directory_path', conf_path() . '/files') . '/geoip_language.txt';
-  if (file_exists($file)) {
-    $data = unserialize(file_get_contents($file));
-    $mapping = isset($data['geoip']) ? $data['geoip'] : NULL;
-  }
-  else {
-    return FALSE;
-  }
-
-  $args = explode('/', $_GET['q']);
-  $prefix = $args[0];
-  if (!in_array($prefix, $mapping)) {
-    global $base_path;
-
-    // no language prefix; geoip detect, then redirect.
-    include_once dirname(dirname(__FILE__)) . '/geoip.module';
-    $country = geoip_country_code();
-    $prefix = ($country && isset($mapping[$country])) ? $mapping[$country] : $data['default'];
-    header('Location: ' . $base_path . $prefix . '/' . $_GET['q']);
-    exit();
-  }
-
-  return FALSE;
-}
diff --git a/geoip_language/geoip_language.info b/geoip_language/geoip_language.info
index 936b7bb..1c66d87 100644
--- a/geoip_language/geoip_language.info
+++ b/geoip_language/geoip_language.info
@@ -3,6 +3,10 @@ description = Language negotiation based on GeoIP detection.
 core = 7.x
 dependencies[] = locale
 dependencies[] = geoip
-files[] = geoip_language.admin.inc
-files[] = geoip_language.fastpath.inc
-files[] = geoip_language.install
+
+; Information added by drupal.org packaging script on 2011-03-10
+version = "7.x-1.x-dev"
+core = "7.x"
+project = "geoip"
+datestamp = "1299715604"
+
diff --git a/geoip_language/geoip_language.install b/geoip_language/geoip_language.install
deleted file mode 100644
index 4dd1814..0000000
--- a/geoip_language/geoip_language.install
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-
-/**
- * @file
- * file_description
- */
-
-/**
- * Implements hook_schema().
- *
- * @return array
- */
-function geoip_language_schema() {
-  $schema['geoip_language'] = array(
-    'description' => 'Table to store geoip country to language mappings.',
-    'fields' => array(
-      'country' => array(
-        'type' => 'char',
-        'length' => 2,
-        'not null' => TRUE,
-        'description' => 'Country code, as defined in http://www.maxmind.com/app/iso3166.',
-      ),
-      'language' => array(
-        'type' => 'varchar',
-        'length' => 12,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => 'Language code, as defined in the languages table.',
-      ),
-    ),
-    'primary key' => array('country'),
-  );
-  return $schema;
-}
-
-/**
- * Implements hook_disable().
- */
-function geoip_language_install() {
-  drupal_install_schema('geoip_language');
-  // Make sure this module loads before most "normal" modules.  This allows the
-  // language negotiation to happen in hook_init() rather than hook_boot().
-  db_query("UPDATE {system} SET weight = -1 WHERE name = 'geoip_language'");
-}
-
-/**
- * Implementation of hook_uninstall().
- */
-function geoip_language_uninstall() {
-  drupal_uninstall_schema('geoip_language');
-}
diff --git a/geoip_language/geoip_language.module b/geoip_language/geoip_language.module
index be07e74..377bf09 100644
--- a/geoip_language/geoip_language.module
+++ b/geoip_language/geoip_language.module
@@ -1,309 +1,308 @@
 <?php
-
-/**
- * @file
- * Language negotiation based on GeoIP detection.
- */
-
 /**
- * Language negotiation option for GeoIP detection.
- *
- * @var integer
+ * Considerations:
+ *   http://drupal.org/node/212505 Google may crawl your site from an IP in Norway, but expects english.
  */
-define('GEOIP_LANGUAGE_NEGOTIATION_PATH', 8);
 
-/**
- * Implements hook_help().
- *
- * @return string
- */
-function geoip_language_help($path, $arg) {
-  switch ($path) {
-    case 'admin/settings/language/geoip':
-      $help = t('<p>This page provides an overview of your site\'s IP detection and language negotiation settings. You may configure which language is chosen when each country is detected from the user\'s IP, using the form below. All detectable languages are listed in the <em>Detected country</em> drop-down list, and all installed languages are listed in t the <em>Language</em> drop-down list. If a country is detected but doesn\'t have an entry in this list, the default language will be used.</p>');
-      return $help;
-  }
-}
 
 /**
  * Implements hook_menu().
- *
- * @return array
  */
 function geoip_language_menu() {
   $items = array();
 
-  $items['admin/settings/language/geoip'] = array(
-    'title' => 'GeoIP',
-    'type' => MENU_LOCAL_TASK,
-    'weight' => 5,
-    'page callback' => 'geoip_language_settings_overview',
-    'access arguments' => array('administer languages'),
-    'file' => 'geoip_language.admin.inc',
-  );
-  $items['admin/settings/language/geoip/delete/%'] = array(
-    'title' => 'Delete GeoIP mapping',
+  $items['admin/config/regional/language/configure/geoip'] = array(
+    'title' => 'Geoip Language configuration',
     'page callback' => 'drupal_get_form',
-    'page arguments' => array('geoip_admin_delete_mapping', 5),
-    'access arguments' => array('administer languages'),
-    'type' => MENU_CALLBACK,
-    'file' => 'geoip_language.admin.inc',
+    'page arguments' => array('geoip_language_admin_settings'),
+    'access arguments' => array('configure geoip'),
   );
 
   return $items;
 }
 
+
 /**
  * Implements hook_language_negotiation_info().
- *
- * @return array
  */
-function geoip_language_init() {
-  // Configured presentation language mode.
-  $mode = variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE);
-
-  $drush = (function_exists('drush_verify_cli') && drush_verify_cli());
-
-  // Only take action if language negotiation is set to GeoIP and there is more
-  // than 1 enabled language.
-  if (!$drush && ($mode == GEOIP_LANGUAGE_NEGOTIATION_PATH) && ((int)variable_get('language_count', 1) > 1)) {
-    geoip_language_negotiation();
-  }
+function geoip_language_language_negotiation_info() {
+  return array(
+    'geoip_language' => array(
+      'callbacks' => array(
+        'language' => 'geoip_language_language_provider_callback',
+      ),
+      'file' => drupal_get_path('module', 'geoip_language') . '/geoip_language.module',
+      'weight' => -4,
+      'name' => t('Geoip Language'),
+      'config' => 'admin/config/regional/language/configure/geoip',
+      'description' => t('Uses Geoip to determine the users language.'),
+      'cache' => 0,
+    ),
+  );
 }
 
-/**
- * Identify language via URL prefix or domain excluding administrative paths.
- * Try to keep as light weight as possible
- *
- * @return string
- *   Language as ISO 639-1 Code
- */
-function geoip_language_negotiation() {
-  // Get a list of enabled languages.
-  $languages = language_list('enabled');
-  $languages = $languages[1];
-
-  // Get the original q, as it is before path un-aliasing.  This is important
-  // because a path alias which is the same as a language prefix will have been
-  // improperly un-aliased and the language prefix will be lost.
-  $query = array();
-  parse_str($_SERVER['QUERY_STRING'], $query);
-  $q = $query['q'];
-
-  // Mostly copied from language_initialize(). Do a basic path prefix lookup to
-  // determine the language.
-  $args = explode('/', $q);
-  $prefix = array_shift($args);
-  // Search prefix within enabled languages.
-  foreach ($languages as $language) {
-    if (!empty($language->prefix) && $language->prefix == $prefix) {
-      // Set the global language object.
-      $GLOBALS['language'] = $language;
-      // Rebuild $_GET['q'] with the language removed.
-      $_GET['q'] = implode('/', $args);
-      // Re-initialize the path.
-      drupal_init_path();
-      // Make PressFlow happy by only storing the language code if there's an
-      // existing session.
-      if (count($_SESSION)) {
-        $_SESSION['geoip_language'] = $language->language;
-      }
-      return;
-    }
-  }
-
-  // Begin fallbacks. At this point, we know that there is not a valid path
-  // prefix, so we must first determine a language, and then do a redirect to
-  // the current path, in that language.
-
-  global $user;
-  // First check to see if a language was previously determined.
-  if (isset($_SESSION['geoip_language']) && isset($languages[$_SESSION['geoip_language']])) {
-    $language = $languages[$_SESSION['geoip_language']];
-  }
-  // Fallback for user-preferred language.
-  elseif ($user->uid && isset($languages[$user->language])) {
-    $language = $languages[$user->language];
-  }
-  // If all else fails, do a GeoIP lookup and redirect.
-  else {
-    $language = geoip_language_detect_language();
-  }
-
-
-  // Set the global language object.
-  $GLOBALS['language'] = $language;
-
-  global $base_path;
-  // Abort the redirect if bootstrap happened outside of index.php or if the
-  // requested path is inside the files directory
-  if (($_SERVER['SCRIPT_NAME'] != $base_path .'index.php')
-    || (strpos($_GET['q'], file_directory_path()) === 0)
-    || ($_SERVER['REQUEST_METHOD'] == 'POST')) {
-    return;
-  }
-
-  // Now that the language is detected, do an absolute redirect to avoid page
-  // caching in the wrong language.
-  $url = url($_GET['q'], array('language' => $language, 'absolute' => TRUE, 'query' => drupal_query_string_encode($_GET, array('q'))));
-  drupal_goto($url, NULL, NULL, 301);
-  exit();
-}
 
 /**
- * Implements custom_url_rewrite_outbound().
- * language_url_rewrite() doesn't add the path prefix for the default language,
- * so we are doing it here.  This lessens the amount of redirection that
- * would occur because of a missing path prefix.
+ * Configure the language mappings
  */
-if (!function_exists('custom_url_rewrite_outbound')) {
-  function custom_url_rewrite_outbound(&$path, &$options, $original_path) {
-    global $language;
+function geoip_language_admin_settings() {
+  $form = array();
 
-    if (variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE) == GEOIP_LANGUAGE_NEGOTIATION_PATH
-      && ((int)variable_get('language_count', 1) > 1)) {
-      // Only modify relative (insite) URLs.
-      if (!$options['external']) {
-
-        // Allow links to bypass the language prefixing.  Helpful for simpletest.
-        // Breaking forms as of 2009-06-22
-//        if (isset($options['geoip_language_no_prefix']) && ($options['geoip_language_no_prefix'] === TRUE)) {
-//          return;
-//        }
+  $form['help'] = array(
+    '#prefix' => '<p>',
+    '#suffix' => '</p>',
+    '#markup' => t('Configure the country to language mappings. TODO (at the moment this form does nothing but display the mappings).'),
+  );
 
-        // Language can be passed as an option, or we go for current language.
-        if (!isset($options['language'])) {
-          $options['language'] = $language;
-        }
+  $header = array(
+    'country' => t('Country'),
+    'language' => t('Language'),
+  );
 
-        if (!empty($options['language']->prefix)) {
-          $options['prefix'] = $options['language']->prefix .'/';
-        }
-      }
-    }
+  $options = array();
+  $mappings = geoip_language_language_list();
+  foreach ($mappings as $country => $mapping) {
+    $options[$country] = array('country' => $country, 'language' => $mapping['default']);
   }
-}
 
-/**
- * Implements hook_form_locale_languages_configure_form_alter().
- */
-function geoip_language_form_locale_languages_configure_form_alter(&$form, $form_state) {
-  $form['language_negotiation']['#options'][GEOIP_LANGUAGE_NEGOTIATION_PATH] = t('Path prefix with GeoIP detection fallback.');
-}
-
-/**
- * API function to create a new mapping.
- *
- * @return array
- */
-function geoip_language_mapping_create($country, $language) {
-  $data = array(
-    'country' => $country,
-    'language' => $language,
+  $form['geoip_language_settings'] = array(
+    '#type' => 'tableselect',
+    '#header' => $header,
+    '#options' => $options,
+    '#empty' => t('No language mappings found.'),
   );
-  drupal_write_record('geoip_language', $data);
-  geoip_language_mappings(TRUE);
-
-  $countries = geoip_country_values();
-  watchdog('geoip_language', 'GeoIP mapping created for %country', array('%country' => $countries[$country]));
 
-  return $data;
+  return system_settings_form($form);
 }
 
-/**
- * API function to delete a mapping.
- *
- * @return boolean
- */
-function geoip_language_mapping_delete($country) {
-  db_query('DELETE FROM {geoip_language} WHERE country="%s"', $country);
-  geoip_language_mappings(TRUE);
-
-  $countries = geoip_country_values();
-  watchdog('geoip_language', 'GeoIP mapping deleted for %country', array('%country' => $countries[$country]));
-}
 
 /**
- * API function to return the country-language mapping.
- *
- * TODO: Serializing to a text file is insane. This should go into the cache
- * table instead.
- *
- * @return array
- *  Associative array key=countrycode, value= Language as ISO 639-1 Code
+ * Determine the site language.
  */
-function geoip_language_mappings($reset = FALSE) {
-  static $mapping = NULL;
-
-  if ($reset || !isset($mapping)) {
-    $file = file_directory_path() .'/geoip_language.txt';
-    if (file_exists($file)) {
-      $data = unserialize(file_get_contents($file));
-      $mapping = isset($data['geoip']) ? $data['geoip'] : NULL;
-    }
-
-    // Build the mapping array and cache it to the filesystem.
-    if ($reset || !$mapping) {
-      $mapping = array();
-      $data = array(
-        'geoip' => array(),
-        'default' => language_default('prefix'),
-      );
-      $result = db_query('SELECT g.*, l.prefix FROM {geoip_language} g INNER JOIN {languages} l on g.language = l.language ORDER BY g.country ASC');
-      while ($row = db_fetch_object($result)) {
-        $mapping[$row->country] = $row->language;
-        $data['geoip'][$row->country] = $row;
-      }
-
-      // Add default
-      $file = file_save_data(serialize($data), 'geoip_language.txt', FILE_EXISTS_REPLACE);
-    }
-  }
-
-  return $mapping;
+function geoip_language_language_provider_callback() {
+  // At this point in the bootstrap we don't
+  // have access to many functions, so this:
+  //   module_load_include('module', 'geoip', 'geoip')
+  // won't work because drupal_get_path has not been loaded.
+  require_once str_replace('geoip_language/geoip_language.module', 'geoip.module', __FILE__);
+
+  // Get the language
+  return geoip_language_language_map(strtolower(geoip_country_code(geoip_ip_address(), true)));
 }
 
 /**
- * Return the language object mapped to the current GeoIP detected country.
- *
- * @return string
- *  Language as ISO 639-1 Code
- *  @link http://de.wikipedia.org/wiki/ISO_639#ISO_639-1  @endlink
+ * Resolve the country to a BCP47 language code.
  */
-function geoip_language_detect_language($reset = FALSE) {
-  static $geoip_language = NULL;
+function geoip_language_language_map($country, $city = 'default') {
+  $lang = geoip_language_language_list();
 
-  if ($reset || !isset($geoip_language)) {
-    // Get a list of enabled languages.
-    $languages = language_list('enabled');
-    $languages = $languages[1];
-    // Get a list of country->language mappings.
-    $mappings = geoip_language_mappings();
-    // GeoIP detect the current country.
-    $country_code = geoip_country_code();
+  // Pick the language
+  $language = NULL;
 
-    // Make sure country_code, the mapping for that country_code, and the enabled
-    // language for that mapping, all exist.
-    if ($country_code && $mappings[$country_code] && $languages[$mappings[$country_code]->language]) {
-      $geoip_language = $languages[$mappings[$country_code]->language];
-    }
-    else {
-      $geoip_language = language_default();
-    }
+  if (isset($lang[$country][$city])) {
+    $language = $lang[$country][$city];
   }
 
-  return $geoip_language;
+  return $language;
 }
 
+
 /**
- * Implements hook_flush_caches().
+ * Map the country to a BCP47 language code. We use an array rather than a
+ * database lookup simply for speed.
  *
- * @return array
- *  Return an empty array - we do the flush ourselfes
+ * We allow other modules to make their modifications via the country_languages hook.
  */
-function geoip_language_flush_caches() {
-  // Reload the geoip cache file.
-  geoip_language_mappings(TRUE);
-
-  return array();
+function geoip_language_language_list() {
+  $lang = array();
+
+  $lang['afghanistan']['default']     = 'ps';
+  $lang['albania']['default']         = 'sq';
+  $lang['algeria']['default']         = 'ar';
+  $lang['andorra']['default']         = 'ca';
+  $lang['angola']['default']          = 'pt';
+  $lang['antigua']['default']         = 'en';
+  $lang['barbuda']['default']         = 'en';
+  $lang['argentina']['default']       = 'es';
+  $lang['armenia']['default']         = 'hy';
+  $lang['australia']['default']       = 'en';
+  $lang['austria']['default']         = 'de';
+  $lang['azerbaijan']['default']      = 'tr';
+  $lang['bahamas']['default']         = 'en';
+  $lang['bahrain']['default']         = 'ar';
+  $lang['barbados']['default']        = 'en';
+  $lang['belarus']['default']         = 'be';
+  $lang['belgium']['default']         = 'nl';
+  $lang['belize']['default']          = 'en';
+  $lang['benin']['default']           = 'fr';
+  $lang['bolivia']['default']         = 'es';
+  $lang['bosnia']['default']          = 'bs';
+  $lang['herzegovina']['default']     = 'bs';
+  $lang['botswana']['default']        = 'tn';
+  $lang['brazil']['default']          = 'pt-br';
+  $lang['brunei']['default']          = 'ms';
+  $lang['bulgaria']['default']        = 'bg';
+  $lang['burkina']['default']         = 'fr';
+  $lang['burundi']['default']         = 'fr';
+  $lang['cambodia']['default']        = 'km';
+  $lang['cameroon']['default']        = 'fr';
+  $lang['canada']['default']          = 'en';
+  $lang['canada']['montreal']         = 'fr';
+  $lang['cape verde']['default']      = 'pt';
+  $lang['central african republic']['default'] = 'fr';
+  $lang['chad']['default']            = 'fr';
+  $lang['chile']['default']           = 'es';
+  $lang['china']['default']           = 'zh-hans';
+  $lang['colombia']['default']        = 'es';
+  $lang['comoros']['default']         = 'ar';
+  $lang['democratic republic of the congo']['default'] = 'fr';
+  $lang['costa rica']['default']      = 'es';
+  $lang['côte d\'ivoire']['default']  = 'fr';
+  $lang['croatia']['default']         = 'cr';
+  $lang['cuba']['default']            = 'es';
+  $lang['cyprus']['default']          = 'gr';
+  $lang['czech republic']['default']  = 'cs';
+  $lang['denmark']['default']         = 'da';
+  $lang['djibouti']['default']        = 'fr';
+  $lang['dominica']['default']        = 'en';
+  $lang['dominican republic']['default'] = 'es';
+  $lang['east timor']['default']      = 'pt';
+  $lang['ecuador']['default']         = 'es';
+  $lang['egypt']['default']           = 'ar';
+  $lang['el salvador']['default']     = 'es';
+  $lang['equatorial guinea']['default'] = 'es';
+  $lang['estonia']['default']         = 'et';
+  $lang['fiji']['default']            = 'en';
+  $lang['finland']['default']         = 'fi';
+  $lang['france']['default']          = 'fr';
+  $lang['gabon']['default']           = 'fr';
+  $lang['gambia']['default']          = 'en';
+  $lang['georgia']['default']         = 'ka';
+  $lang['germany']['default']         = 'de';
+  $lang['dey']['default']             = 'de';
+  $lang['ghana']['default']           = 'en';
+  $lang['greece']['default']          = 'el';
+  $lang['grenada']['default']         = 'en';
+  $lang['guatemala']['default']       = 'es';
+  $lang['guinea']['default']          = 'fr';
+  $lang['guinea-bissau']['default']   = 'pt';
+  $lang['guyana']['default']          = 'en';
+  $lang['haiti']['default']           = 'cr';
+  $lang['honduras']['default']        = 'es';
+  $lang['hungary']['default']         = 'hu';
+  $lang['iceland']['default']         = 'is';
+  $lang['india']['default']           = 'hi';
+  $lang['iran']['default']            = 'fa';
+  $lang['iraq']['default']            = 'ar';
+  $lang['ireland']['default']         = 'en';
+  $lang['israel']['default']          = 'he';
+  $lang['italy']['default']           = 'it';
+  $lang['jamaica']['default']         = 'en';
+  $lang['japan']['default']           = 'ja';
+  $lang['jordan']['default']          = 'ar';
+  $lang['kazakhstan']['default']      = 'kk';
+  $lang['kenya']['default']           = 'en';
+  $lang['kiribati']['default']        = 'en';
+  $lang['korea, north']['default']    = 'ko';
+  $lang['korea, south']['default']    = 'ko';
+  $lang['kuwait']['default']          = 'ar';
+  $lang['kyrgyzstan']['default']      = 'ky';
+  $lang['laos']['default']            = 'la';
+  $lang['latvia']['default']          = 'lv';
+  $lang['lebanon']['default']         = 'ar';
+  $lang['lesotho']['default']         = 'en';
+  $lang['liberia']['default']         = 'en';
+  $lang['libya']['default']           = 'ar';
+  $lang['liechtenstein']['default']   = 'de';
+  $lang['lithuania']['default']       = 'lt';
+  $lang['luxembourg']['default']      = 'lb';
+  $lang['macedonia']['default']       = 'mk';
+  $lang['malawi']['default']          = 'ny';
+  $lang['malaysia']['default']        = 'ms';
+  $lang['maldives']['default']        = 'dv';
+  $lang['mali']['default']            = 'fr';
+  $lang['malta']['default']           = 'mt';
+  $lang['mauritania']['default']      = 'ar';
+  $lang['mauritius']['default']       = 'cr';
+  $lang['mexico']['default']          = 'es';
+  $lang['micronesia']['default']      = 'en';
+  $lang['moldova']['default']         = 'mo';
+  $lang['monaco']['default']          = 'fr';
+  $lang['mongolia']['default']        = 'mn';
+  $lang['montenegro']['default']      = 'sr';
+  $lang['morocco']['default']         = 'ar';
+  $lang['mozambique']['default']      = 'pt';
+  $lang['myanmar']['default']         = 'my';
+  $lang['namibia']['default']         = 'af';
+  $lang['nepal']['default']           = 'ne';
+  $lang['netherlands']['default']     = 'nl';
+  $lang['new Zealand']['default']     = 'en';
+  $lang['nicaragua']['default']       = 'es';
+  $lang['niger']['default']           = 'fr';
+  $lang['nigeria']['default']         = 'en';
+  $lang['norway']['default']          = 'no';
+  $lang['oman']['default']            = 'ar';
+  $lang['palestinian state']['default'] = 'ar';
+  $lang['panama']['default']          = 'es';
+  $lang['paraguay']['default']        = 'es';
+  $lang['peru']['default']            = 'es';
+  $lang['philippines']['default']     = 'fil';
+  $lang['poland']['default']          = 'pl';
+  $lang['portugal']['default']        = 'pt-pt';
+  $lang['qatar']['default']           = 'ar';
+  $lang['romania']['default']         = 'ro';
+  $lang['russia']['default']          = 'ru';
+  $lang['st. kitts and nevis']['default'] = 'en';
+  $lang['st. lucia']['default']       = 'en';
+  $lang['st. vincent and the grenadines']['default'] = 'en';
+  $lang['san marino']['default']      = 'it';
+  $lang['são tomé and príncipe']['default'] = 'pt';
+  $lang['saudi arabia']['default']    = 'ar';
+  $lang['senegal']['default']         = 'fr';
+  $lang['seychelles']['default']      = 'cr';
+  $lang['sierra leone']['default']    = 'en';
+  $lang['singapore']['default']       = 'zh-hans';
+  $lang['slovakia']['default']        = 'sk';
+  $lang['slovenia']['default']        = 'sl';
+  $lang['solomon islands']['default'] = 'en';
+  $lang['somalia']['default']         = 'so';
+  $lang['south africa']['default']    = 'zu';
+  $lang['spain']['default']           = 'es';
+  $lang['sri lanka']['default']       = 'si';
+  $lang['sudan']['default']           = 'ar';
+  $lang['suriname']['default']        = 'nl';
+  $lang['swaziland']['default']       = 'en';
+  $lang['sweden']['default']          = 'sv';
+  $lang['switzerland']['default']     = 'de';
+  $lang['syria']['default']           = 'ar';
+  $lang['taiwan']['default']          = 'zh-hans';
+  $lang['tajikistan']['default']      = 'tg';
+  $lang['tanzania']['default']        = 'sw';
+  $lang['thailand']['default']        = 'th';
+  $lang['togo']['default']            = 'fr';
+  $lang['tonga']['default']           = 'to';
+  $lang['trinidad and tobago']['default'] = 'en';
+  $lang['tunisia']['default']         = 'ar';
+  $lang['turkey']['default']          = 'tr';
+  $lang['turkmenistan']['default']    = 'tk';
+  $lang['uganda']['default']          = 'en';
+  $lang['ukraine']['default']         = 'uk';
+  $lang['united arab emirates']['default'] = 'ar';
+  $lang['united kingdom']['default']  = 'en';
+  $lang['united states']['default']   = 'en';
+  $lang['uruguay']['default']         = 'es';
+  $lang['uzbekistan']['default']      = 'uz';
+  $lang['vanuatu']['default']         = 'bi';
+  $lang['vatican city (holy see)']['default'] = 'it';
+  $lang['venezuela']['default']       = 'es';
+  $lang['vietnam']['default']         = 'vi';
+  $lang['western sahara']['default']  = 'ar';
+  $lang['yemen']['default']           = 'ar';
+  $lang['zambia']['default']          = 'en';
+  $lang['zimbabwe']['default']        = 'en';
+
+  // Allow other modules to alter the language mapping
+  drupal_alter('country_languages', $lang);
+
+  return $lang;
 }
diff --git a/geoip_language/geoip_language.test b/geoip_language/geoip_language.test
deleted file mode 100644
index 1ce47a4..0000000
--- a/geoip_language/geoip_language.test
+++ /dev/null
@@ -1,133 +0,0 @@
-<?php
-
-/**
- * @file
- * Test suite for geoip_language.module
- */
-
-class geoipLanguageTestCase extends DrupalWebTestCase {
-  /**
-   * Implementation of getInfo().
-   */
-  function getInfo() {
-    return array(
-      'name' => t('GeoIP Language'),
-      'description' => t('Test suite for the geoip_language module.'),
-      'group' => t('GeoIP'),
-    );
-  }
-
-  /**
-   * Implementation of setUp().
-   */
-  function setUp() {
-    parent::setUp('locale', 'geoip', 'geoip_language');
-
-    $this->admin_user = $this->drupalCreateUser(array('administer languages', 'administer site configuration', 'access administration pages'));
-    $this->visitor = $this->drupalCreateUser(array('access content'));
-    $this->drupalLogin($this->admin_user);
-
-    // Make sure default language has a prefix.
-    $this->drupalPost('admin/settings/language/edit/en', array('prefix' => 'global'), t('Save language'));
-    // Add and map french/france
-    $this->addLanguage('fr');
-    geoip_language_mapping_create('FR', 'fr');
-    // Add and map german/germany
-    $this->addLanguage('de');
-    geoip_language_mapping_create('DE', 'de');
-
-    // reset language in the testing thread so url's get formatted properly.
-    $GLOBALS['language'] = language_default();
-
-    variable_set('geoip_debug', TRUE);
-    variable_set('language_negotiation', GEOIP_LANGUAGE_NEGOTIATION_PATH);
-  }
-
-  /**
-   * Enable the specified language if it has not been already.
-   *
-   * @param string $language_code
-   *   The language code to enable.
-   */
-  function addLanguage($language_code) {
-    // Check to make sure that language has not already been installed.
-    $this->drupalGet('admin/settings/language');
-
-    if (strpos($this->drupalGetContent(), 'enabled[' . $language_code . ']') === FALSE) {
-      // Doesn't have language installed so add it.
-      $edit = array();
-      $edit['langcode'] = $language_code;
-      $this->drupalPost('admin/settings/language/add', $edit, t('Add language'));
-
-      $languages = language_list('language', TRUE); // Make sure not using cached version.
-      $this->assertTrue(array_key_exists($language_code, $languages), t('%language language was installed successfully.', array('%language' => $languages[$language_code]->name)));
-
-      if (array_key_exists($language_code, $languages)) {
-        $this->assertRaw(t('The language %language has been created and can now be used.', array('%language' => $languages[$language_code]->name)), t('Language has been created.'));
-      }
-    }
-    else {
-      // Ensure that it is enabled.0
-      $this->drupalPost(NULL, array('enabled[' . $language_code . ']' => TRUE), t('Save configuration'));
-
-      $this->assertRaw(t('Configuration saved.'), t('Language successfully enabled.'));
-    }
-  }
-
-  function dsm($object) {
-    $this->error('<pre>'.check_plain(print_r($object,1)).'</pre>');
-  }
-
-  function testMappingCrud() {
-    $mappings = geoip_language_mappings(TRUE);
-    $this->assertFalse(array_key_exists('US', $mappings), t('No mapping for US'));
-    $this->drupalPost('admin/settings/language/geoip', array('country' => 'US', 'language' => 'en'), t('Add mapping'), array('language' => $GLOBALS['language']));
-
-    $mappings = geoip_language_mappings(TRUE);
-    $this->assertEqual($mappings['US'], 'en', t('Mapping created for US => en'));
-
-    $this->drupalPost('admin/settings/language/geoip/delete/US', array(), t('Delete'));
-    $mappings = geoip_language_mappings(TRUE);
-    $this->assertFalse(array_key_exists('US', $mappings), t('US mapping deleted.'));
-  }
-
-  function testDefaultLanguageNegotiation() {
-    global $base_url, $base_path;
-    $languages = language_list('language', TRUE);
-
-    // US ip address, should map to en language and force a redirect. Not using
-    // url() or any of its derivatives, so as not to taint this url.
-    $this->drupalGet($base_url . $base_path .'node?geoip_debug=140.211.166.6');
-    $url = url('node', array('absolute' => TRUE, 'language' => $languages['en']));
-    $this->assertEqual($this->getUrl(), $url, t('Redirect to default language (%url).', array('%url' => $this->getUrl())));
-
-    // Browse directly to a french page.  No redirect should happen.
-    $this->drupalGet('node', array('language' => $languages['fr']));
-    $url = url('node', array('absolute' => TRUE, 'language' => $languages['fr']));
-    $this->assertEqual($this->getUrl(), $url, t('No redirect for non-default language (%url).', array('%url' => $this->getUrl())));
-
-    // Now french should be in the session.  Browsing directly to a page without
-    // a prefix should redirect me to the french version.
-    $this->drupalGet($base_url . $base_path .'node');
-    $url = url('node', array('absolute' => TRUE, 'language' => $languages['fr']));
-    $this->assertEqual($this->getUrl(), $url, t('Redirect to the language stored in the session (%url).', array('%url' => $this->getUrl())));
-
-    // Now just for good measure make sure that nothing weird happens when
-    // browsing directly to the a page with the default langauge's prefix.
-    $this->drupalGet('node', array('language' => $languages['en']));
-    $url = url('node', array('absolute' => TRUE, 'language' => $languages['en']));
-    $this->assertEqual($this->getUrl(), $url, t('No redirect for default language prefix (%url).', array('%url' => $this->getUrl())));
-  }
-
-  function testFrenchLanguageNegotiation() {
-    global $base_url, $base_path;
-    $languages = language_list('language', TRUE);
-
-    // FR ip address, should map to fr language and force a redirect. Not using
-    // url() or any of its derivatives, so as not to taint this url.
-    $this->drupalGet($base_url . $base_path .'node?geoip_debug=81.255.22.101');
-    $url = url('node', array('absolute' => TRUE, 'language' => $languages['fr']));
-    $this->assertEqual($this->getUrl(), $url, t('Redirect to french path (%url).', array('%url' => $this->getUrl())));
-  }
-
-}
