diff --git a/pathauto.admin.inc b/pathauto.admin.inc
index b210386..5585d3b 100644
--- a/pathauto.admin.inc
+++ b/pathauto.admin.inc
@@ -14,9 +14,7 @@
  * @see system_settings_form()
  */
 function pathauto_patterns_form($form, $form_state) {
-  // Call the hook on all modules - an array of 'settings' objects is returned
-  $all_settings = module_invoke_all('pathauto', 'settings');
-  foreach ($all_settings as $settings) {
+  foreach (pathauto_get_settings() as $settings) {
     $module = $settings->module;
     $patterndescr = $settings->patterndescr;
     $patterndefault = $settings->patterndefault;
@@ -264,8 +262,7 @@ function pathauto_bulk_update_form() {
     '#default_value' => array(),
   );
 
-  $pathauto_settings = module_invoke_all('pathauto', 'settings');
-  foreach ($pathauto_settings as $settings) {
+  foreach (pathauto_get_settings() as $settings) {
     if (!empty($settings->batch_update_callback)) {
       $form['#update_callbacks'][$settings->batch_update_callback] = $settings;
       $form['update']['#options'][$settings->batch_update_callback] = $settings->groupheader;
diff --git a/pathauto.inc b/pathauto.inc
index 9699aa0..a7e06cf 100644
--- a/pathauto.inc
+++ b/pathauto.inc
@@ -538,8 +538,9 @@ function _pathauto_set_alias(array $path, $existing_alias = NULL, $op = NULL) {
     return FALSE;
   }
 
-  // Skip replacing the current alias with an identical alias
-  if (empty($existing_alias) || $existing_alias['alias'] != $path['alias']) {
+  // Skip replacing the current alias with an identical alias, in a multilingual
+  // world, identical alias don't mean the same.
+  if (empty($existing_alias) || $existing_alias['alias'] != $path['alias'] || $existing_alias['language'] != $path['language']) {
     $path += array('pathauto' => TRUE, 'original' => $existing_alias);
 
     // If there is already an alias, respect some update actions.
diff --git a/pathauto.module b/pathauto.module
index 5027dec..1dc36e2 100644
--- a/pathauto.module
+++ b/pathauto.module
@@ -837,14 +837,14 @@ function taxonomy_pathauto($op) {
  * Implements hook_taxonomy_term_insert().
  */
 function pathauto_taxonomy_term_insert($term) {
-  pathauto_taxonomy_term_update_alias($term, 'insert');
+  pathauto_preprocess_taxonomy_term_alias($term, 'insert');
 }
 
 /**
  * Implements hook_taxonomy_term_update().
  */
 function pathauto_taxonomy_term_update($term) {
-  pathauto_taxonomy_term_update_alias($term, 'update', array('alias children' => TRUE));
+  pathauto_preprocess_taxonomy_term_alias($term, 'update', array('alias children' => TRUE));
 }
 
 /**
@@ -903,7 +903,7 @@ function pathauto_taxonomy_term_update_alias(stdClass $term, $op, array $options
   );
 
   // Skip processing if the term has no pattern.
-  if (!pathauto_pattern_load_by_entity($module, $term->vocabulary_machine_name)) {
+  if (!pathauto_pattern_load_by_entity($module, $term->vocabulary_machine_name, $options['language'])) {
     return FALSE;
   }
 
@@ -938,7 +938,7 @@ function pathauto_taxonomy_term_update_alias_multiple(array $tids, $op, array $o
 
   $terms = taxonomy_term_load_multiple($tids);
   foreach ($terms as $term) {
-    pathauto_taxonomy_term_update_alias($term, $op, $options);
+    pathauto_preprocess_taxonomy_term_alias($term, $op, $options);
   }
 
   if (!empty($options['message'])) {
@@ -1216,3 +1216,26 @@ function pathauto_features_pipe_taxonomy_alter(&$pipe, $data, $export) {
     $pipe['variable'][] = "pathauto_taxonomy_term_{$vocabulary}_pattern";
   }
 }
+
+/**
+ * Returns a list of pathauto settings defined by all modules.
+ */
+function pathauto_get_settings() {
+  $settings = &drupal_static(__FUNCTION__);
+  if (!$settings) {
+    $settings = module_invoke_all('pathauto', 'settings');
+    $settings = array_combine(array_map(function ($o) { return $o->module; }, $settings), $settings);
+
+    // Allow other module to alter the pathauto settings.
+    drupal_alter('pathauto', $settings);
+  }
+  return $settings;
+}
+
+/**
+ * Allow modules to alter the term before being created.
+ */
+function pathauto_preprocess_taxonomy_term_alias($term, $op, $options = array()) {
+  drupal_alter('pathauto_preprocess_alias', $term, $op, $options);
+  pathauto_taxonomy_term_update_alias($term, $op, $options);
+}
