diff --git a/includes/common.inc b/includes/common.inc
index ce369332f5321eb6ae8134a3f6e028529aeac7e8..d4461f9396a3d3a76d22b6ef88b3f69ec5f44845 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -7492,8 +7492,15 @@ function entity_get_controller($entity_type) {
  *   The type of entity, i.e. 'node', 'user'.
  * @param $entities
  *   The entity objects which are being prepared for view, keyed by object ID.
+ * @param $langcode
+ *   (optional) A language code to be used for rendering. Defaults to the global
+ *   content language of the current request.
  */
-function entity_prepare_view($entity_type, $entities) {
+function entity_prepare_view($entity_type, $entities, $langcode = NULL) {
+  if (!isset($langcode)) {
+    $langcode = $GLOBALS['language_content']->language;
+  }
+
   // To ensure hooks are only run once per entity, check for an
   // entity_view_prepared flag and only process items without it.
   // @todo: resolve this more generally for both entity and field level hooks.
@@ -7509,7 +7516,7 @@ function entity_prepare_view($entity_type, $entities) {
   }
 
   if (!empty($prepare)) {
-    module_invoke_all('entity_prepare_view', $prepare, $entity_type);
+    module_invoke_all('entity_prepare_view', $prepare, $entity_type, $langcode);
   }
 }
 
diff --git a/modules/comment/comment.module b/modules/comment/comment.module
index 55c6fcbb0e2c0bca4882d6df4633f86b7c214f70..0fc38f8ddaeade6f147fc87d9cdf1897840a0756 100644
--- a/modules/comment/comment.module
+++ b/modules/comment/comment.module
@@ -988,8 +988,8 @@ function comment_build_content($comment, $node, $view_mode = 'full', $langcode =
   $comment->content = array();
 
   // Build fields content.
-  field_attach_prepare_view('comment', array($comment->cid => $comment), $view_mode);
-  entity_prepare_view('comment', array($comment->cid => $comment));
+  field_attach_prepare_view('comment', array($comment->cid => $comment), $view_mode, $langcode);
+  entity_prepare_view('comment', array($comment->cid => $comment), $langcode);
   $comment->content += field_attach_view('comment', $comment, $view_mode, $langcode);
 
   $comment->content['links'] = array(
@@ -1091,8 +1091,8 @@ function comment_links($comment, $node) {
  *   An array in the format expected by drupal_render().
  */
 function comment_view_multiple($comments, $node, $view_mode = 'full', $weight = 0, $langcode = NULL) {
-  field_attach_prepare_view('comment', $comments, $view_mode);
-  entity_prepare_view('comment', $comments);
+  field_attach_prepare_view('comment', $comments, $view_mode, $langcode);
+  entity_prepare_view('comment', $comments, $langcode);
 
   $build = array(
     '#sorted' => TRUE,
diff --git a/modules/field/field.attach.inc b/modules/field/field.attach.inc
index 82aabc054fc7aa97c2ca9ec7b876a270bdc55c7b..3b15c76c87bc65e90028fcfe2557956892d49132 100644
--- a/modules/field/field.attach.inc
+++ b/modules/field/field.attach.inc
@@ -257,9 +257,9 @@ function _field_invoke($op, $entity_type, $entity, &$a = NULL, &$b = NULL, $opti
  *  - 'deleted': If TRUE, the function will operate on deleted fields
  *    as well as non-deleted fields. If unset or FALSE, only
  *    non-deleted fields are operated on.
- *  - 'language': A language code or an array of language codes keyed by field
- *    name. It will be used to narrow down to a single value the available
- *    languages to act on.
+ *  - 'language': A language code or an array of arrays of language codes keyed
+ *    by entity id and field name. It will be used to narrow down to a single
+ *    value the available languages to act on.
  *
  * @return
  *   An array of returned values keyed by entity id.
@@ -311,7 +311,8 @@ function _field_invoke_multiple($op, $entity_type, $entities, &$a = NULL, &$b =
         // Unless a language suggestion is provided we iterate on all the
         // available languages.
         $available_languages = field_available_languages($entity_type, $field);
-        $languages = _field_language_suggestion($available_languages, $options['language'], $field_name);
+        $language = !empty($options['language'][$id]) ? $options['language'][$id] : $options['language'];
+        $languages = _field_language_suggestion($available_languages, $language, $field_name);
         foreach ($languages as $langcode) {
           $grouped_items[$field_id][$langcode][$id] = isset($entity->{$field_name}[$langcode]) ? $entity->{$field_name}[$langcode] : array();
         }
@@ -1074,8 +1075,13 @@ function field_attach_delete_revision($entity_type, $entity) {
  *   An array of entities, keyed by entity id.
  * @param $view_mode
  *   View mode, e.g. 'full', 'teaser'...
+ * @param $langcode
+ *   (Optional) The language the field values are to be shown in. If no language
+ *   is provided the current language is used.
  */
-function field_attach_prepare_view($entity_type, $entities, $view_mode) {
+function field_attach_prepare_view($entity_type, $entities, $view_mode, $langcode = NULL) {
+  $options = array('language' => array());
+
   // To ensure hooks are only run once per entity, only process items without
   // the _field_view_prepared flag.
   // @todo: resolve this more generally for both entity and field level hooks.
@@ -1085,17 +1091,22 @@ function field_attach_prepare_view($entity_type, $entities, $view_mode) {
       // Add this entity to the items to be prepared.
       $prepare[$id] = $entity;
 
+      // Determine the actual language to display for each field, given the
+      // languages available in the field data.
+      $options['language'][$id] = field_language($entity_type, $entity, NULL, $langcode);
+
       // Mark this item as prepared.
       $entity->_field_view_prepared = TRUE;
     }
   }
 
+  $null = NULL;
   // First let the field types do their preparation.
-  _field_invoke_multiple('prepare_view', $entity_type, $prepare);
+  _field_invoke_multiple('prepare_view', $entity_type, $prepare, $null, $null, $options);
   // Then let the formatters do their own specific massaging.
   // field_default_prepare_view() takes care of dispatching to the correct
   // formatters according to the display settings for the view mode.
-  _field_invoke_multiple_default('prepare_view', $entity_type, $prepare, $view_mode);
+  _field_invoke_multiple_default('prepare_view', $entity_type, $prepare, $view_mode, $null, $options);
 }
 
 /**
diff --git a/modules/node/node.module b/modules/node/node.module
index a002e24c31fb773116bc36c101c1c21fce0cfb23..d19cf2985a54a2ce8b8ff26bee5f842be49d9391 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -1350,15 +1350,15 @@ function node_build_content($node, $view_mode = 'full', $langcode = NULL) {
   // The 'view' hook can be implemented to overwrite the default function
   // to display nodes.
   if (node_hook($node, 'view')) {
-    $node = node_invoke($node, 'view', $view_mode);
+    $node = node_invoke($node, 'view', $view_mode, $langcode);
   }
 
   // Build fields content.
   // In case of a multiple view, node_view_multiple() already ran the
   // 'prepare_view' step. An internal flag prevents the operation from running
   // twice.
-  field_attach_prepare_view('node', array($node->nid => $node), $view_mode);
-  entity_prepare_view('node', array($node->nid => $node));
+  field_attach_prepare_view('node', array($node->nid => $node), $view_mode, $langcode);
+  entity_prepare_view('node', array($node->nid => $node), $langcode);
   $node->content += field_attach_view('node', $node, $view_mode, $langcode);
 
   // Always display a read more link on teasers because we have no way
@@ -2517,8 +2517,8 @@ function node_feed($nids = FALSE, $channel = array()) {
  *   An array in the format expected by drupal_render().
  */
 function node_view_multiple($nodes, $view_mode = 'teaser', $weight = 0, $langcode = NULL) {
-  field_attach_prepare_view('node', $nodes, $view_mode);
-  entity_prepare_view('node', $nodes);
+  field_attach_prepare_view('node', $nodes, $view_mode, $langcode);
+  entity_prepare_view('node', $nodes, $langcode);
   $build = array();
   foreach ($nodes as $node) {
     $build['nodes'][$node->nid] = node_view($node, $view_mode, $langcode);
diff --git a/modules/system/system.api.php b/modules/system/system.api.php
index e38641f48ca0c1cae5c166731d654acb83c9cf21..9f56abade313407536d85b183690429c4e64ffd9 100644
--- a/modules/system/system.api.php
+++ b/modules/system/system.api.php
@@ -502,8 +502,10 @@ function hook_admin_paths_alter(&$paths) {
  *   The entities keyed by entity ID.
  * @param $type
  *   The type of entities being loaded (i.e. node, user, comment).
+ * @param $langcode
+ *   The language to display the entity in.
  */
-function hook_entity_prepare_view($entities, $type) {
+function hook_entity_prepare_view($entities, $type, $langcode) {
   // Load a specific node into the user object for later theming.
   if ($type == 'user') {
     $nodes = mymodule_get_user_nodes(array_keys($entities));
diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module
index f08df601e3b78a470c12d5fb832f470775afb2c8..71f3edbd9166803ffdea3b0d4d5ed5b484eb6aec 100644
--- a/modules/taxonomy/taxonomy.module
+++ b/modules/taxonomy/taxonomy.module
@@ -682,8 +682,8 @@ function taxonomy_term_view($term, $view_mode = 'full', $langcode = NULL) {
     $langcode = $GLOBALS['language_content']->language;
   }
 
-  field_attach_prepare_view('taxonomy_term', array($term->tid => $term), $view_mode);
-  entity_prepare_view('taxonomy_term', array($term->tid => $term));
+  field_attach_prepare_view('taxonomy_term', array($term->tid => $term), $view_mode, $langcode);
+  entity_prepare_view('taxonomy_term', array($term->tid => $term), $langcode);
 
   $build = array(
     '#theme' => 'taxonomy_term',
diff --git a/modules/user/user.module b/modules/user/user.module
index 0c437ad41bfaea4c4ff77be8514e752bd10d024c..40023d3d12b659bc6dd04ff13897de7e639f3716 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -2523,8 +2523,8 @@ function user_build_content($account, $view_mode = 'full', $langcode = NULL) {
   $account->content = array();
 
   // Build fields content.
-  field_attach_prepare_view('user', array($account->uid => $account), $view_mode);
-  entity_prepare_view('user', array($account->uid => $account));
+  field_attach_prepare_view('user', array($account->uid => $account), $view_mode, $langcode);
+  entity_prepare_view('user', array($account->uid => $account), $langcode);
   $account->content += field_attach_view('user', $account, $view_mode, $langcode);
 
   // Populate $account->content with a render() array.