diff --git a/language_fallback.fallback.inc b/language_fallback.fallback.inc
index 754d352..5943a16 100644
--- a/language_fallback.fallback.inc
+++ b/language_fallback.fallback.inc
@@ -8,13 +8,14 @@ class localeWithFallback implements ArrayAccess {
 
   private $langcode;
   private $cache = array();
-  private $fallback;
+  private $fallbacks;
 
-  public function __construct($langcode, $fallback = '') {
+  public function __construct($langcode) {
     $languages = language_list();
     $this->langcode = isset($languages[$langcode]) ? $langcode : language_default('language');
     $this->cache = array();
-    $this->fallback = isset($languages[$fallback]) ? $fallback : language_default('langauge');
+    $fallbacks = language_fallback_fallback($langcode);
+    $this->fallbacks = $fallbacks ? $fallbacks : array();
   }
 
   public function offsetExists($offset) {
@@ -23,7 +24,7 @@ class localeWithFallback implements ArrayAccess {
 
   public function &offsetGet($offset) {
     if (!isset($this->cache[$offset])) {
-      $this->cache[$offset] = new localeContextWithFallback($this->langcode, $this->fallback, $offset);
+      $this->cache[$offset] = new localeContextWithFallback($this->langcode, $this->fallbacks, $offset);
     }
     return $this->cache[$offset];
   }
@@ -53,51 +54,44 @@ class localeContextWithFallback implements ArrayAccess {
   private $context = '';
   private $fallback;
 
-  public function __construct($langcode, $fallback, $context) {
+  public function __construct($langcode, $fallbacks, $context) {
     $languages = language_list();
-    $this->first_language = isset($languages[$langcode]) ? $langcode : language_default('language');
-    $this->second_language = isset($languages[$fallback]) ? $fallback : language_default('language');
+    $this->first_language = $langcode;
+    $this->second_language = $fallbacks ? array_shift($fallbacks) : language_default('language');
     $this->context = $context;
     $second_lang_obj = $languages[$this->second_language];
+
     // If the fallback is the default language, we don't need a
     // localeContextWithFallback since the default language does not have a
     // fallback. Otherwise we use a localeContextWithFallback so we gradually
     // fall back to the default language (cascading fallbacks, see
     // http://drupal.org/node/1877880 for more info.
-    if ($this->second_language != language_default('language')) {
-      $this->fallback = new localeContextWithFallback($this->second_language, isset($languages[$second_lang_obj->fallback]) ? $second_lang_obj->fallback : language_default('language'), $context);
+    if (!empty($fallbacks)) {
+      $this->fallback = new localeContextWithFallback($this->second_language,$fallbacks, $context);
     }
   }
 
   public function offsetGet($offset) {
-    $translation = $offset;
-    if (function_exists('locale')) {
-      $locale_t = &drupal_static('locale');
-      $translation = locale($offset, $this->context, $this->first_language);
-      // Check whether string returned was a translation or the untranslated
-      // original. Have to check locale()'s static variable, because just
-      // comparing the strings might be misleading.
-      // (Stupid example: (en) village == (fr) village.).
-      // Locale sets the value to TRUE if the string is not found (if it is found
-      // it sets the value to that string. So if the value === TRUE we know there
-      // was no translation found for this language and we can check the fallback.
-      if ($locale_t[$this->first_language][$this->context][$offset] === TRUE) {
-        $translation = $this->fallback[$offset];
-      }
+    $locale_t = &drupal_static('locale');
+    $translation = locale($offset, $this->context, $this->first_language);
+    // Check whether string returned was a translation or the untranslated
+    // original. Have to check locale()'s static variable, because just
+    // comparing the strings might be misleading.
+    // (Stupid example: (en) village == (fr) village.).
+    // Locale sets the value to TRUE if the string is not found (if it is found
+    // it sets the value to that string. So if the value === TRUE we know there
+    // was no translation found for this language and we can check the fallback.
+    if ($locale_t[$this->first_language][$this->context][$offset] === TRUE && $this->first_language != 'en') {
+      $translation = $this->fallback[$offset];
     }
     return $translation;
   }
 
   public function offsetExists($offset) {
-    if (function_exists('locale')) {
-      $locale_t = &drupal_static('locale');
-      $translation = locale($offset, $this->context, $this->first_language);
-      if ($locale_t[$this->first_language][$this->context][$offset] !== TRUE) {
-        return TRUE;
-      }
-      else {
-        return isset($this->fallback[$offset]);
-      }
+    $locale_t = &drupal_static('locale');
+    $translation = locale($offset, $this->context, $this->first_language);
+    if ($locale_t[$this->first_language][$this->context][$offset] !== TRUE) {
+      return TRUE;
     }
     else {
       return isset($this->fallback[$offset]);
diff --git a/language_fallback.module b/language_fallback.module
index 23886ea..a529375 100644
--- a/language_fallback.module
+++ b/language_fallback.module
@@ -5,61 +5,10 @@
  * Hook implementations for the Language Fallback module.
  */
 
-/**
- * Implements hook_form_alter().
- */
-function language_fallback_form_alter(&$form, &$form_state, $form_id) {
-  if ($form_id == 'locale_languages_predefined_form' || $form_id == 'locale_languages_custom_form' || $form_id == 'locale_languages_edit_form') {
-    // Store language for edit form or FALSE on create forms.
-    $editmode = isset($form['langcode_view']) ? $form['langcode']['#value'] : FALSE;
-    $default_lang = language_default();
-    $languages = language_list();
-    $options = locale_language_list();
-
-    // Alter label of default language.
-    if (isset($options[$default_lang->language])) {
-      $options = array('' => t('Default language (@lang)', array('@lang' => $default_lang->name))) + $options;
-      unset($options[$default_lang->language]);
-    }
-
-    // Add native name.
-    foreach ($options as $key => $option) {
-      if (!empty($languages[$key]->native)) {
-        $options[$key] .= " ({$languages[$key]->native})";
-      }
-    }
+function language_fallback_fallback($langcode) {
+  $fallbacks = array();
+  drupal_alter('language_fallback_alter', $fallbacks, $langcode);
 
-    // Add select to create/edit form.
-    $key = $form_id == 'locale_languages_predefined_form' ? 'language list' : 'custom language';
-    $form[$key]['fallback'] = array(
-      '#type' => 'select',
-      '#title' => t('Language fallback'),
-      '#default_value' => '',
-      '#options' => $options,
-      '#description' => t('This language will be used as a fallback for text that has no translation in the selected language.'),
-    );
-    $form['#submit'][] = 'language_fallback_add_language_submit';
-
-    // Remove current language in edit mode, set default.
-    if ($editmode) {
-      unset($form[$key]['fallback']['#options'][$editmode]);
-      $form[$key]['fallback']['#default_value'] = $languages[$editmode]->fallback;
-    }
-  }
+  return $fallbacks;
 }
 
-/**
- * Form submit callback.
- */
-function language_fallback_add_language_submit($form, &$form_state) {
-  db_update('languages')
-    ->fields(array('fallback' => $form_state['values']['fallback']))
-    ->condition('language', $form_state['values']['langcode'])
-    ->execute();
-  if (!empty($form_state['values']['fallback'])) {
-    variable_set('locale_custom_strings_' . $form_state['values']['langcode'], new localeWithFallback($form_state['values']['langcode'], $form_state['values']['fallback']));
-  }
-  else {
-    variable_del('locale_custom_strings_' . $form_state['values']['langcode']);
-  }
-}
diff --git a/modules/language_fallback_country/language_fallback_country.css b/modules/language_fallback_country/language_fallback_country.css
new file mode 100644
index 0000000..9f64ca7
--- /dev/null
+++ b/modules/language_fallback_country/language_fallback_country.css
@@ -0,0 +1,14 @@
+.field-name-language-fallback td .field-name-language-fallback-country,
+.field-name-language-fallback td .field-name-language-fallback-languages,
+.field-name-language-fallback td>.form-submit {
+  float: left;
+  margin-right: 5px;
+}
+
+.field-name-language-fallback td .field-name-language-fallback-country select {
+  width: 100px;
+}
+
+.field-name-language-fallback .tabledrag-toggle-weight-wrapper {
+  display: none;
+}
diff --git a/modules/language_fallback_country/language_fallback_country.info b/modules/language_fallback_country/language_fallback_country.info
new file mode 100644
index 0000000..78aa7a1
--- /dev/null
+++ b/modules/language_fallback_country/language_fallback_country.info
@@ -0,0 +1,10 @@
+name = Language Fallback Country
+description = This module allows you to specify a language fallback for each defined language, so entity translation can fallback to another language.
+package = Multilingual - Internationalization
+core = 7.x
+
+dependencies[] = language_fallback
+dependencies[] = multiple_selects
+dependencies[] = field_collection
+dependencies[] = countries
+dependencies[] = languagefield
diff --git a/modules/language_fallback_country/language_fallback_country.install b/modules/language_fallback_country/language_fallback_country.install
new file mode 100644
index 0000000..55da43c
--- /dev/null
+++ b/modules/language_fallback_country/language_fallback_country.install
@@ -0,0 +1,133 @@
+<?php
+
+/**
+ * @file
+ * Schema, update and install function for Language Fallback Country.
+ */
+
+/**
+ * Implements hook_schema().
+ */
+function language_fallback_country_schema() {
+  $schema['language_fallback'] = array(
+    'description' => '',
+    'fields' => array(
+      'lfid' => array(
+        'description' => '',
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'language' => array(
+        'description' => '',
+        'type' => 'varchar',
+        'length' => 12,
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('lfid'),
+    'unique keys' => array('language' => array('language')),
+  );
+  return $schema;
+}
+
+/**
+ * Implements hook_enable().
+ */
+function language_fallback_country_enable() {
+   $field = field_info_field('language_fallback');
+   $instance = field_info_instance('language_fallback', 'language_fallback', 'language_fallback');
+   if (empty($field)) {
+     $field = array(
+       'field_name' => 'language_fallback',
+       'type' => 'field_collection',
+       'entity_types' => array('language_fallback'),
+       'cardinality' => -1,
+       'locked' => TRUE,
+       );
+     $field = field_create_field($field);
+   }
+   if (empty($instance)) {
+     $instance = array(
+       'field_name' => 'language_fallback',
+       'entity_type' => 'language_fallback',
+       'bundle' =>'language_fallback',
+       'label' => 'Language Fallback',
+       'widget' => array('type' => 'field_collection_embed'),
+       'settings' => array(),
+       'display' => array(),
+       );
+     $instance = field_create_instance($instance);
+   }
+    $field = field_info_field('language_fallback_country');
+    $instance = field_info_instance('field_collection_item', 'language_fallback_country', 'language_fallback');
+  if (empty($field)) {
+    $field = array(
+      'field_name' => 'language_fallback_country',
+      'type' => 'country',
+      'entity_types' => array('field_collection_item', 'user'),
+      'locked' => TRUE,
+      );
+    $field = field_create_field($field);
+  }
+  if (empty($instance)) {
+    $instance = array(
+      'field_name' => 'language_fallback_country',
+      'entity_type' => 'field_collection_item',
+      'bundle' =>'language_fallback',
+      'label' => 'Country',
+      'widget' => array('type' => 'options_select'),
+      'settings' => array(),
+      'display' => array(),
+      );
+    $instance = field_create_instance($instance);
+  }
+    $instance = field_info_instance('user', 'language_fallback_country', 'user');
+    if (empty($instance)) {
+      $instance = array(
+        'field_name' => 'language_fallback_country',
+        'entity_type' => 'user',
+        'bundle' =>'user',
+        'label' => 'Country',
+        'widget' => array('type' => 'options_select'),
+        'settings' => array(),
+        'display' => array(),
+        );
+      $instance = field_create_instance($instance);
+    }
+    $field = field_info_field('language_fallback_languages');
+    $instance = field_info_instance('field_collection_item', 'language_fallback_languages', 'language_fallback');
+  if (empty($field)) {
+    $field = array(
+      'field_name' => 'language_fallback_languages',
+      'type' => 'language_field',
+      'entity_types' => array('field_collection_item'),
+      'cardinality' => -1,
+      'settings' => array('enabled' => LANGUAGEFIELD_LANGUAGES_INSTALLED),
+      'locked' => TRUE,
+      );
+    $field = field_create_field($field);
+  }
+  if (empty($instance)) {
+    $instance = array(
+      'field_name' => 'language_fallback_languages',
+      'entity_type' => 'field_collection_item',
+      'bundle' =>'language_fallback',
+      'label' => 'Languages',
+      'widget' => array('type' => 'multiple_selects'),
+      'settings' => array(),
+      'display' => array(),
+      );
+    $instance = field_create_instance($instance);
+  }
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function language_fallback_country_uninstall() {
+  field_delete_field('language_fallback_languages');
+  field_delete_field('language_fallback_country');
+  field_delete_field('language_fallback');
+  field_purge_batch(3);
+}
diff --git a/modules/language_fallback_country/language_fallback_country.module b/modules/language_fallback_country/language_fallback_country.module
new file mode 100644
index 0000000..d835ad3
--- /dev/null
+++ b/modules/language_fallback_country/language_fallback_country.module
@@ -0,0 +1,138 @@
+<?php
+
+/**
+ * @file
+ * Hook implementations for the Language Fallback module.
+ */
+
+/**
+ * Implements hook_entity_info().
+ */
+function language_fallback_country_entity_info() {
+  $return = array(
+    'language_fallback' => array(
+      'label' => t('Language Fallback'),
+      'controller class' => 'EntityAPIControllerExportable',
+      'base table' => 'language_fallback',
+      'fieldable' => TRUE,
+      'entity keys' => array(
+        'id' => 'lfid',
+        'name' => 'language',
+      ),
+      'bundles' => array(
+        'language_fallback' => array(
+          'label' => t('Language Fallback'),
+        ),
+      ),
+      'view modes' => array(),
+    ),
+  );
+  return $return;
+}
+
+function language_fallback_country_load_multiple_by_name($name = NULL) {
+  $language_fallbacks = entity_load_multiple_by_name('language_fallback', isset($name) ? array($name) : FALSE);
+  return isset($name) ? reset($language_fallbacks) : $language_fallbacks;
+}
+
+/**
+ * Implements hook_form_alter().
+ */
+function language_fallback_country_form_alter(&$form, &$form_state, $form_id) {
+  if ($form_id == 'locale_languages_predefined_form' || $form_id == 'locale_languages_custom_form' || $form_id == 'locale_languages_edit_form') {
+    // Store language for edit form or FALSE on create forms.
+    $langcode = isset($form['langcode_view']) ? $form['langcode']['#value'] : NULL;
+    $default_lang = language_default();
+    $languages = language_list();
+    $options = locale_language_list();
+
+    // Alter label of default language.
+    if (isset($options[$default_lang->language])) {
+      $options = array('' => t('Default language (@lang)', array('@lang' => $default_lang->name))) + $options;
+      unset($options[$default_lang->language]);
+    }
+
+    // Add native name.
+    foreach ($options as $key => $option) {
+      if (!empty($languages[$key]->native)) {
+        $options[$key] .= " ({$languages[$key]->native})";
+      }
+    }
+
+    // Add select to create/edit form.
+    $key = $form_id == 'locale_languages_predefined_form' ? 'language list' : 'custom language';
+    $form[$key] = array();
+    $language_fallback = language_fallback_country_load_multiple_by_name($langcode);
+    $form['#language_fallback'] = $language_fallback;
+    field_attach_form('language_fallback', $language_fallback, $form[$key], $form_state);
+    $form[$key]['language_fallback']['#weight'] = 10;
+    $form['#attached']['css'] = array(
+      drupal_get_path('module', 'language_fallback_country') . '/language_fallback_country.css',
+    );
+    $form['#submit'][] = 'language_fallback_country_add_language_submit';
+  }
+}
+
+/**
+ * Form submit callback.
+ */
+function language_fallback_country_add_language_submit($form, &$form_state) {
+  $language_fallback = $form['#language_fallback'];
+  if (!$language_fallback) {
+    $language_fallback = new stdClass();
+  }
+  $language_fallback->language = $form_state['values']['langcode'];
+  field_attach_submit('language_fallback', $language_fallback, $form, $form_state);
+  entity_get_controller('language_fallback')->save($language_fallback);
+}
+
+function language_fallback_country() {
+  global $user;
+  $account = user_load($user->uid);
+  if ($items = field_get_items('user', $account, 'language_fallback_country')) {
+    return $items[0]['iso2'];
+  }
+  if (module_exists('smart_ip')) {
+    $location = smart_ip_get_location(ip_address());
+    if (isset($location['country_code'])) {
+      $account->language_fallback_country[LANGUAGE_NONE][0]['iso2'] = $location['country_code'];
+      field_attach_update('user', $account);
+      return $location['country_code'];
+    }
+  }
+  return FALSE;
+}
+
+function language_fallback_country_language_fallback_alter(&$fallbacks, $langcode) {
+  if ($language_fallback = language_fallback_country_load_multiple_by_name($langcode)) {
+    $wrapper = entity_metadata_wrapper('language_fallback', $language_fallback);
+    $country_fallbacks = array();
+    foreach ($wrapper->language_fallback as $language_fallback) {
+      $languages = array();
+      $language_fallback = $language_fallback->value();
+      if ($language_fallback->language_fallback_languages) {
+        foreach ($language_fallback->language_fallback_languages[LANGUAGE_NONE] as $language) {
+          $languages[] = $language['value'];
+        }
+      }
+      if ($language_fallback->language_fallback_country) {
+        $country = $language_fallback->language_fallback_country[LANGUAGE_NONE][0]['iso2'];
+        $country_fallbacks[$country] = $languages;
+      } else {
+        $fallbacks = $languages;
+      }
+    }
+    if ($country = language_fallback_country()) {
+      if (isset($country_fallbacks[$country]) && !empty($country_fallbacks[$country])) {
+        $fallbacks = $country_fallbacks[$country];
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_widget_info_alter().
+ */
+function language_fallback_country_field_widget_info_alter(&$info) {
+  $info['multiple_selects']['field types'][] = 'language_field';
+}
diff --git a/modules/language_fallback_entity/language_fallback_entity.info b/modules/language_fallback_entity/language_fallback_entity.info
new file mode 100644
index 0000000..bfa3a9f
--- /dev/null
+++ b/modules/language_fallback_entity/language_fallback_entity.info
@@ -0,0 +1,6 @@
+name = Language Fallback Entity
+description = This module allows you to specify a language fallback for each defined language, so entity translation can fallback to another language.
+package = Multilingual - Internationalization
+core = 7.x
+
+dependencies[] = language_fallback
diff --git a/modules/language_fallback_entity/language_fallback_entity.module b/modules/language_fallback_entity/language_fallback_entity.module
new file mode 100644
index 0000000..1615058
--- /dev/null
+++ b/modules/language_fallback_entity/language_fallback_entity.module
@@ -0,0 +1,16 @@
+<?php
+
+/**
+ * @file
+ * Hook implementations for the Language Fallback Entity module.
+ */
+
+/**
+ * Implements hook_language_fallback_candidates_alter().
+ */
+function language_fallback_entity_language_fallback_candidates_alter(array &$fallback_candidates) {
+  global $language;
+  if ($fallbacks = language_fallback_fallback($language->language)) {
+    $fallback_candidates = $fallbacks;
+  }
+}
