diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php
index 4a067ab..9719fc0 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -596,6 +596,8 @@ function hook_node_load($nodes, $types) {
  *   - "view"
  * @param object $account
  *   The user object to perform the access check operation on.
+ * @param object $langcode
+ *   The language code to perform the access check operation on.
  *
  * @return integer
  *   - NODE_ACCESS_ALLOW: if the operation is to be allowed.
@@ -604,7 +606,7 @@ function hook_node_load($nodes, $types) {
  *
  * @ingroup node_access
  */
-function hook_node_access($node, $op, $account) {
+function hook_node_access($node, $op, $account, $langcode) {
   $type = is_string($node) ? $node : $node->type;
 
   $configured_types = node_permissions_get_configured_types();
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 287c5af..e216973 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -2848,13 +2848,21 @@ function node_form_system_themes_admin_form_submit($form, &$form_state) {
  * @param $account
  *   (optional) A user object representing the user for whom the operation is to
  *   be performed. Determines access for a user other than the current user.
+ * @param $langcode
+ *   (optional) Language code for the variant of the node. Different language
+ *   variants might have different permissions associated. If NULL, the
+ *   original langcode of the node is used.
  *
  * @return
  *   TRUE if the operation may be performed, FALSE otherwise.
  *
  * @see node_menu()
+ *
+ * @todo
+ *   Add langcode support to node_access schema / queries.
+ *   http://drupal.org/node/1658846
  */
-function node_access($op, $node, $account = NULL) {
+function node_access($op, $node, $account = NULL, $langcode = NULL) {
   $rights = &drupal_static(__FUNCTION__, array());
 
   if (!$node || !in_array($op, array('view', 'update', 'delete', 'create'), TRUE)) {
@@ -2872,18 +2880,25 @@ function node_access($op, $node, $account = NULL) {
 
   $cid = is_object($node) ? $node->nid : $node;
 
+  // If no language code was provided, default to the node's langcode or
+  // to an empty langcode if a node type was requested. The latter is purely
+  // for caching purposes.
+  if (empty($langcode)) {
+    $langcode = is_object($node) ? $node->langcode : '';
+  }
+
   // If we've already checked access for this node, user and op, return from
   // cache.
-  if (isset($rights[$account->uid][$cid][$op])) {
-    return $rights[$account->uid][$cid][$op];
+  if (isset($rights[$account->uid][$cid][$langcode][$op])) {
+    return $rights[$account->uid][$cid][$langcode][$op];
   }
 
   if (user_access('bypass node access', $account)) {
-    $rights[$account->uid][$cid][$op] = TRUE;
+    $rights[$account->uid][$cid][$langcode][$op] = TRUE;
     return TRUE;
   }
   if (!user_access('access content', $account)) {
-    $rights[$account->uid][$cid][$op] = FALSE;
+    $rights[$account->uid][$cid][$langcode][$op] = FALSE;
     return FALSE;
   }
 
@@ -2892,19 +2907,19 @@ function node_access($op, $node, $account = NULL) {
   // - At least one module says to grant access.
   // If no module specified either allow or deny, we fall back to the
   // node_access table.
-  $access = module_invoke_all('node_access', $node, $op, $account);
+  $access = module_invoke_all('node_access', $node, $op, $account, $langcode);
   if (in_array(NODE_ACCESS_DENY, $access, TRUE)) {
-    $rights[$account->uid][$cid][$op] = FALSE;
+    $rights[$account->uid][$cid][$langcode][$op] = FALSE;
     return FALSE;
   }
   elseif (in_array(NODE_ACCESS_ALLOW, $access, TRUE)) {
-    $rights[$account->uid][$cid][$op] = TRUE;
+    $rights[$account->uid][$cid][$langcode][$op] = TRUE;
     return TRUE;
   }
 
   // Check if authors can view their own unpublished nodes.
-  if ($op == 'view' && !$node->status && user_access('view own unpublished content', $account) && $account->uid == $node->uid && $account->uid != 0) {
-    $rights[$account->uid][$cid][$op] = TRUE;
+  if ($op == 'view' && !$node->get('status', $langcode) && user_access('view own unpublished content', $account) && $account->uid == $node->get('uid', $langcode) && $account->uid != 0) {
+    $rights[$account->uid][$cid][$langcode][$op] = TRUE;
     return TRUE;
   }
 
@@ -2937,13 +2952,13 @@ function node_access($op, $node, $account = NULL) {
       $result =  (bool) $query
         ->execute()
         ->fetchField();
-      $rights[$account->uid][$cid][$op] = $result;
+      $rights[$account->uid][$cid][$langcode][$op] = $result;
       return $result;
     }
-    elseif (is_object($node) && $op == 'view' && $node->status) {
+    elseif (is_object($node) && $op == 'view' && $node->get('status', $langcode)) {
       // If no modules implement hook_node_grants(), the default behavior is to
       // allow all users to view published nodes, so reflect that here.
-      $rights[$account->uid][$cid][$op] = TRUE;
+      $rights[$account->uid][$cid][$langcode][$op] = TRUE;
       return TRUE;
     }
   }
