diff --git a/core/modules/block/block.js b/core/modules/block/block.js
index 72b5673..67cbb31 100644
--- a/core/modules/block/block.js
+++ b/core/modules/block/block.js
@@ -32,6 +32,17 @@ Drupal.behaviors.blockSettingsSummary = {
       return vals.join(', ');
     });
 
+    $('fieldset#edit-langcode', context).drupalSetSummary(function (context) {
+      var vals = [];
+      $('input[type="checkbox"]:checked', context).each(function () {
+        vals.push($.trim($(this).next('label').text()));
+      });
+      if (!vals.length) {
+        vals.push(Drupal.t('Not restricted'));
+      }
+      return vals.join(', ');
+    });
+
     $('fieldset#edit-role', context).drupalSetSummary(function (context) {
       var vals = [];
       $('input[type="checkbox"]:checked', context).each(function () {
diff --git a/core/modules/language/language.install b/core/modules/language/language.install
index ecf637d..87a1606 100644
--- a/core/modules/language/language.install
+++ b/core/modules/language/language.install
@@ -71,6 +71,33 @@ function language_schema() {
       'list' => array('weight', 'name'),
     ),
   );
+  $schema['block_langcode'] = array(
+    'description' => 'Sets up display criteria for blocks based on langcode',
+    'fields' => array(
+      'module' => array(
+        'type' => 'varchar',
+        'length' => 64,
+        'not null' => TRUE,
+        'description' => "The block's origin module, from {block}.module.",
+      ),
+      'delta' => array(
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'description' => "The block's unique delta within module, from {block}.delta.",
+      ),
+      'langcode' => array(
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'description' => "The machine-readable name of this language from {language}.langcode.",
+      ),
+    ),
+    'primary key' => array('module', 'delta', 'langcode'),
+    'indexes' => array(
+      'langcode' => array('langcode'),
+    ),
+  );
   return $schema;
 }
 
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index 20f7c62..962b771 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -186,6 +186,17 @@ function language_delete($langcode) {
 }
 
 /**
+ * Implements hook_modules_uninstalled().
+ *
+ * Cleans up {block_langcode} table from modules' blocks. 
+ */
+function language_modules_uninstalled($modules) {
+	db_delete('block_langcode')
+  ->condition('module', $modules, 'IN')
+  ->execute();
+}
+
+/**
  * Implements hook_css_alter().
  *
  * This function checks all CSS files currently added via drupal_add_css() and
@@ -211,3 +222,95 @@ function language_css_alter(&$css) {
     }
   }
 }
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ *
+ * Adds per language block visibility options to block configuration form.
+ *
+ * @see language_form_block_admin_configure_submit()
+ * @see block_admin_configure()
+ */
+function language_form_block_admin_configure_alter(&$form, &$form_state) {
+  $default_langcode_options = db_query("SELECT langcode FROM {block_langcode} WHERE module = :module AND delta = :delta", array(
+    ':module' => $form['module']['#value'],
+    ':delta' => $form['delta']['#value'],
+  ))->fetchCol();
+
+  // Fetch the enabled languages.
+  $enabled_languages = language_list(TRUE);
+  foreach ($enabled_languages as $language) {
+    $langcodes_options[$language->langcode] = t($language->name);
+  }
+  $form['visibility']['langcode'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Languages'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#group' => 'visibility',
+    '#weight' => 5,
+  );
+  $form['visibility']['langcode']['langcodes'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Show block for specific languages'),
+    '#default_value' => $default_langcode_options,
+    '#options' => $langcodes_options,
+    '#description' => t('Show this block only if the current language is of the given language(s). If you select no language, there will be no language-specific limitation.'),
+  );
+  $form['#submit'][] = 'language_form_block_admin_configure_submit';
+}
+
+/**
+ * Form submission handler for locale_form_block_admin_configure_alter().
+ */
+function language_form_block_admin_configure_submit($form, &$form_state) {
+  db_delete('block_langcode')
+      ->condition('module', $form_state['values']['module'])
+      ->condition('delta', $form_state['values']['delta'])
+      ->execute();
+  $query = db_insert('block_langcode')->fields(array(
+    'langcode', 'module', 'delta'
+  ));
+  foreach (array_filter($form_state['values']['langcodes']) as $langcode) {
+    $query->values(array(
+      'langcode' => $langcode,
+      'module' => $form_state['values']['module'],
+      'delta' => $form_state['values']['delta'],
+    ));
+  }
+  $query->execute();
+}
+
+/**
+ * Implements hook_block_list_alter().
+ *
+ * Hide the blocks that have been disabled for langcodes visibility setting.
+ */
+function language_block_list_alter(&$blocks) {
+  global $language_interface, $theme_key;
+
+  $result = db_query('SELECT module, delta, langcode FROM {block_langcode}');
+  $block_langcodes = array();
+  foreach ($result as $record) {
+    $block_langcodes[$record->module][$record->delta][$record->langcode] = TRUE;
+  }
+  foreach ($blocks as $key => $block) {
+    // Any module using this alter should inspect the data before changing it,
+    // to ensure it is what they expect.
+    if (!isset($block->theme) || !isset($block->status) || $block->theme != $theme_key || $block->status != 1) {
+      // This block was added by a contrib module, leave it in the list.
+      continue;
+    }
+
+    if (!isset($block_langcodes[$block->module][$block->delta])) {
+      // No language setting for this block, leave it in the list.
+      continue;
+    }
+
+    if (!isset($block_langcodes[$block->module][$block->delta][$language_interface->langcode])) {
+      // This block should not be displayed with the active language, remove
+      // from the list.
+      unset($blocks[$key]);
+    }
+  }
+}
diff --git a/core/modules/simpletest/tests/upgrade/drupal-7.language.database.php b/core/modules/simpletest/tests/upgrade/drupal-7.language.database.php
index 99dc318..4ddf0f8 100644
--- a/core/modules/simpletest/tests/upgrade/drupal-7.language.database.php
+++ b/core/modules/simpletest/tests/upgrade/drupal-7.language.database.php
@@ -553,6 +553,39 @@ db_insert('locales_target')->fields(array(
 ))
 ->execute();
 
+  // Add block_langcode table from language.install schema.
+  db_create_table('block_langcode', array(
+    'fields' => array(
+      'module' => array(
+        'type' => 'varchar',
+        'length' => 64,
+        'not null' => TRUE,
+      ),
+      'delta' => array(
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+      ),
+      'langcode' => array(
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array(
+      'module',
+      'delta',
+      'langcode'
+    ),
+    'indexes' => array(
+      'langcode' => array(
+        'langcode',
+      ),
+    ),
+    'module' => 'language',
+    'name' => 'block_langcode',
+  ));
+
 // Set up variables needed for language support.
 db_insert('variable')->fields(array(
   'name',
