diff --git a/file_entity.file.inc b/file_entity.file.inc
index 96c5a1e..df726ec 100644
--- a/file_entity.file.inc
+++ b/file_entity.file.inc
@@ -272,38 +272,14 @@ function file_entity_set_title_alt_properties($files, $language = NULL) {
   if (!isset($language)) {
     $language = $GLOBALS['language'];
   }
-
-  $alt = variable_get('file_entity_alt', '[file:field_file_image_alt_text]');
-  $title = variable_get('file_entity_title', '[file:field_file_image_title_text]');
-
   $replace_options = array(
     'clear' => TRUE,
     'sanitize' => FALSE,
     'language' => $language,
   );
-
   foreach ($files as $file) {
-    // Load alt and title text from fields.
-    if (!empty($alt)) {
-      $output = token_replace($alt, array('file' => $file), $replace_options);
-
-      if (!empty($output)) {
-        // @todo Remove once https://www.drupal.org/node/1713164 is fixed.
-        // There is currently no way to get the raw alt text returned from the
-        // token so we revert the encoding done during tokenization.
-        $file->alt = decode_entities($output);
-      }
-    }
-    if (!empty($title)) {
-      $output = token_replace($title, array('file' => $file), $replace_options);
-
-      if (!empty($output)) {
-        // @todo Remove once https://www.drupal.org/node/1713164 is fixed.
-        // There is currently no way to get the raw title text returned from the
-        // token so we revert the encoding done during tokenization.
-        $file->title = decode_entities($output);
-      }
-    }
+    $file->title = file_entity_replace_title($file, $replace_options);
+    $file->alt = file_entity_replace_alt($file, $replace_options);
   }
 }
 
diff --git a/file_entity.file_api.inc b/file_entity.file_api.inc
index ae9e06d..b5350fc 100644
--- a/file_entity.file_api.inc
+++ b/file_entity.file_api.inc
@@ -257,6 +257,23 @@ function file_view_file($file, $displays = 'full', $langcode = NULL) {
     }
   }
 
+  // Since $file->alt and $file->title were set in file_entity_file_load()
+  // (which is a language-agnostic hook) they will not be in the correct
+  // language if the file is being displayed in a language other than the
+  // default one. Set them again here, using the correct language. This must
+  // run after hook_file_displays_alter() since the Media module sets
+  // $file->alt and $file->title again during that hook.
+  if ($langcode != $GLOBALS['language_content']->language) {
+    $languages = language_list();
+    if (isset($languages[$langcode])) {
+      $replace_options = array(
+        'language' => $languages[$langcode],
+      );
+      $file->title = file_entity_replace_title($file, $replace_options);
+      $file->alt = file_entity_replace_alt($file, $replace_options);
+    }
+  }
+
   // Attempt to display the file with each of the possible displays. Stop after
   // the first successful one. See file_displays() for details.
   $element = NULL;
diff --git a/file_entity.module b/file_entity.module
index 6c8c406..53970eb 100644
--- a/file_entity.module
+++ b/file_entity.module
@@ -1249,6 +1249,81 @@ function file_entity_file_formatter_file_field_settings($form, &$form_state, $se
   }
 }
 
+/**
+ * Replace file entity title text.
+ *
+ * @param $file
+ *   The file entity.
+ * @param $replace_options
+ *   (Optional) Options to pass to token_replace().
+ * @param $title
+ *   (Optional) The title text to use.
+ *
+ * @return string
+ *   Returns the replaced title text.
+ */
+function file_entity_replace_title($file, $replace_options = array(), $title = NULL) {
+  $replace_options += array(
+    'clear' => TRUE,
+    'sanitize' => FALSE,
+  );
+
+  $title_default = '[file:field_file_image_title_text]';
+  if (!isset($title)) {
+    $title = variable_get('file_entity_title', $title_default);
+  }
+  // If the defaults are not changed then inlining replacement is much faster
+  // than dealing with the token system.
+  if ($title === $title_default) {
+    $title_items = field_get_items('file', $file, 'field_file_image_title_text');
+    return $title_items ? $title_items[0]['value'] : '';
+  }
+  elseif (!empty($title)) {
+    $token_replaced = token_replace($title, array('file' => $file), $replace_options);
+    return decode_entities($token_replaced); // Filter out possible XSS.
+  }
+
+  return '';
+}
+
+/**
+ * Replace file entity alt.
+ *
+ * @param $file
+ *   The file entity.
+ * @param $replace_options
+ *   (Optional) Options to pass to token_replace().
+ * @param $alt
+ *   (Optional) The alt text to use.
+ *
+ * @return string
+ *   Returns the replaced alt text.
+ */
+function file_entity_replace_alt($file, $replace_options = array(), $alt = NULL) {
+  $replace_options += array(
+    'clear' => TRUE,
+    'sanitize' => FALSE,
+  );
+
+  $alt_default = '[file:field_file_image_alt_text]';
+
+  if (!isset($alt)) {
+    $alt = variable_get('file_entity_alt', $alt_default);
+  }
+
+  // If the defaults are not changed then inlining replacement is much faster
+  // than dealing with the token system.
+  if ($alt === $alt_default) {
+    $alt_items = field_get_items('file', $file, 'field_file_image_alt_text');
+    return $alt_items ? $alt_items[0]['value'] : '';
+  }
+  elseif (!empty($alt)) {
+    $token_replaced = token_replace($alt, array('file' => $file), $replace_options);
+    return decode_entities($token_replaced); // Filter out possible XSS.
+  }
+}
+
+
 /**
  * Implements hook_file_formatter_FORMATTER_view().
  *
@@ -1289,8 +1364,8 @@ function file_entity_file_formatter_file_image_view($file, $display, $langcode)
         '#path' => $file->uri,
         '#width' => isset($file->override['attributes']['width']) ? $file->override['attributes']['width'] : $file->metadata['width'],
         '#height' => isset($file->override['attributes']['height']) ? $file->override['attributes']['height'] : $file->metadata['height'],
-        '#alt' => token_replace($display['settings']['alt'], array('file' => $file), $replace_options),
-        '#title' => token_replace($display['settings']['title'], array('file' => $file), $replace_options),
+        '#alt' => file_entity_replace_alt($file, $replace_options, $display['settings']['alt']),
+        '#title' => file_entity_replace_title($file, $replace_options, $display['settings']['title']),
       );
     }
     else {
@@ -1299,8 +1374,8 @@ function file_entity_file_formatter_file_image_view($file, $display, $langcode)
         '#path' => $file->uri,
         '#width' => isset($file->override['attributes']['width']) ? $file->override['attributes']['width'] : $file->metadata['width'],
         '#height' => isset($file->override['attributes']['height']) ? $file->override['attributes']['height'] : $file->metadata['height'],
-        '#alt' => token_replace($display['settings']['alt'], array('file' => $file), $replace_options),
-        '#title' => token_replace($display['settings']['title'], array('file' => $file), $replace_options),
+        '#alt' => file_entity_replace_alt($file, $replace_options, $display['settings']['alt']),
+        '#title' => file_entity_replace_title($file, $replace_options, $display['settings']['title']),
       );
     }
     return $element;
