diff --git a/core/modules/language/config/language.mappings.yml b/core/modules/language/config/language.mappings.yml
index f7fc321..c2022f1 100644
--- a/core/modules/language/config/language.mappings.yml
+++ b/core/modules/language/config/language.mappings.yml
@@ -6,7 +6,5 @@ zh: 'zh-hans' # Default Chinese to simplified script
 zh-tw: 'zh-hant' # Taiwan Chinese in traditional script
 zh-hk: 'zh-hant' # Hong Kong Chinese in traditional script
 zh-mo: 'zh-hant' # Macao Chinese in traditional script
-zh-cht: 'zh-hant' # traditional Chinese
 zh-cn: 'zh-hans' # PRC Mainland Chinese in simplified script
 zh-sg: 'zh-hans' # Singapore Chinese in simplified script
-zh-chs: 'zh-hans' # simplified Chinese
diff --git a/core/modules/language/language.admin.inc b/core/modules/language/language.admin.inc
index 475eba2..fa6231b 100644
--- a/core/modules/language/language.admin.inc
+++ b/core/modules/language/language.admin.inc
@@ -101,6 +101,95 @@ function theme_language_negotiation_configure_form($variables) {
 }
 
 /**
+ * Builds the browser language negotiation method configuration form.
+ *
+ * @see language_negotiation_configure_browser_form_validate()
+ * @see language_negotiation_configure_browser_form_submit()
+ *
+ * @ingroup forms
+ */
+function language_negotiation_configure_browser_form($form, &$form_state) {
+  $form = array();
+
+  // Initialize a language list to the ones available, including English.
+  $languages = language_list();
+
+  $existing_languages = array();
+  foreach ($languages as $langcode => $language) {
+    $existing_languages[$langcode] = $language->name;
+  }
+
+  // If we have no languages available, present the list of predefined languages
+  // only. If we do have already added languages, set up two option groups with
+  // the list of existing and then predefined languages.
+  if (empty($existing_languages)) {
+    $language_options = language_admin_predefined_list();
+  }
+  else {
+    $language_options = array(
+      t('Existing languages') => $existing_languages,
+      t('Languages not yet added') => language_admin_predefined_list(),
+    );
+  }
+
+  $form['mappings'] = array(
+    '#tree' => TRUE,
+    '#theme' => 'language_negotiation_configure_browser_form_table',
+  );
+
+  $mappings = language_get_browser_drupal_langcode_mappings();
+  foreach ($mappings as $browser_langcode => $drupal_langcode) {
+    $form['mappings'][$browser_langcode] = array(
+      'browser_langcode' => array(
+        '#title' => t('Browser language code'),
+        '#title_display' => 'invisible',
+        '#type' => 'textfield',
+        '#default_value' => $browser_langcode,
+        '#size' => 20,
+        '#required' => TRUE,
+      ),
+      'drupal_langcode' => array(
+        '#title' => t('Site language'),
+        '#title_display' => 'invisible',
+        '#type' => 'select',
+        '#options' => $language_options,
+        '#default_value' => $drupal_langcode,
+        '#required' => TRUE,
+      ),
+    );
+  }
+
+  // Add empty row.
+  $form['new_mapping'] = array(
+    '#type' => 'details',
+    '#title' => t('Add a new mapping'),
+    '#collapsed' => TRUE,
+    '#tree' => TRUE,
+  );
+  $form['new_mapping']['browser_langcode'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Browser language code'),
+    '#description' => t('Use language codes as <a href="@w3ctags">defined by the W3C</a> for interoperability. <em>Examples: "en", "en-gb" and "zh-hant".</em>', array('@w3ctags' => 'http://www.w3.org/International/articles/language-tags/')),
+    '#default_value' => '',
+    '#size' => 20,
+  );
+  $form['new_mapping']['drupal_langcode'] = array(
+    '#type' => 'select',
+    '#title' => t('Site language'),
+    '#options' => $language_options,
+    '#default_value' => '',
+  );
+
+  $form['actions']['#type'] = 'actions';
+  $form['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save configuration'),
+  );
+
+  return $form;
+}
+
+/**
  * Theme browser configuration form as table.
  *
  * @param $variables
@@ -120,9 +209,6 @@ function theme_language_negotiation_configure_browser_form_table($variables) {
     $links['delete'] = array(
       'title' => t('Delete'),
       'href' => "admin/config/regional/language/detection/browser/delete/$key",
-      'attributes' => array(
-        'class' => array('image-style-link'),
-      ),
     );
     $row[] = array(
       'data' => array(
@@ -136,7 +222,7 @@ function theme_language_negotiation_configure_browser_form_table($variables) {
 
   $header = array(
     t('Browser language code'),
-    t('Drupal language'),
+    t('Site language'),
     t('Operations'),
   );
 
@@ -144,7 +230,8 @@ function theme_language_negotiation_configure_browser_form_table($variables) {
     '#type' => 'table',
     '#header' => $header,
     '#rows' => $rows,
-    '#attributes' => array('id' => 'lang-neg-browser'),
+    '#empty' => t('No browser language mappings available.'),
+    '#attributes' => array('id' => 'language-negotiation-browser'),
   );
   $output = drupal_render($table);
 
@@ -152,6 +239,59 @@ function theme_language_negotiation_configure_browser_form_table($variables) {
 }
 
 /**
+ * Browser language negotiation form validation.
+ *
+ * @see language_negotiation_configure_browser_form_submit()
+ */
+function language_negotiation_configure_browser_form_validate($form, &$form_state) {
+  // Array to check if all browser language codes are unique.
+  $unique_values = array();
+
+  // Check all mappings.
+  $mappings = array();
+  if (isset($form_state['values']['mappings'])) {
+    $mappings = $form_state['values']['mappings'];
+    foreach ($mappings as $key => $data) {
+      // Make sure browser_langcode is unique.
+      if (array_key_exists($data['browser_langcode'], $unique_values)) {
+        form_set_error('mappings][' . $key . '][browser_langcode', t('Browser language codes must be unique.'));
+      }
+      elseif (preg_match('/[^a-z\-]/', $data['browser_langcode'])) {
+        form_set_error('mappings][' . $key . '][browser_langcode', t('Browser language codes can only contain lowercase letters and a hyphen(-).'));
+      }
+      $unique_values[$data['browser_langcode']] = $data['drupal_langcode'];
+    }
+  }
+
+  // Check new mapping.
+  $data = $form_state['values']['new_mapping'];
+  if (!empty($data['browser_langcode'])) {
+    // Make sure browser_langcode is unique.
+    if (array_key_exists($data['browser_langcode'], $unique_values)) {
+      form_set_error('mappings][new_mapping][browser_langcode', t('Browser language codes must be unique.'));
+    }
+    elseif (preg_match('/[^a-z\-]/', $data['browser_langcode'])) {
+      form_set_error('mappings][new_mapping][browser_langcode', t('Browser language codes can only contain lowercase letters and a hyphen(-).'));
+    }
+    $unique_values[$data['browser_langcode']] = $data['drupal_langcode'];
+  }
+
+  $form_state['mappings'] = $unique_values;
+}
+
+/**
+ * Browser language negotiation form submit.
+ */
+function language_negotiation_configure_browser_form_submit($form, &$form_state) {
+  $mappings = $form_state['mappings'];
+  if (!empty($mappings)) {
+    language_set_browser_drupal_langcode_mappings($mappings);
+    drupal_set_message(t('The configuration options have been saved.'));
+  }
+  $form_state['redirect'] = 'admin/config/regional/language/detection';
+}
+
+/**
  * Returns the content language settings form.
  *
  * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index 3cb07b3..ba44b8c 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -48,7 +48,7 @@ function language_help($path, $arg) {
       return $output;
 
     case 'admin/config/regional/language/detection/browser':
-      $output = '<p>' . t('Browsers use different language codes to refer to the same languages. You can add and edit mappings from browser language codes to the <a href="@configure-languages">languages used by Drupal</a>.', array('@configure-languages' => url('admin/config/regional/language'))) . '</p>';
+      $output = '<p>' . t('Browsers use different language codes to refer to the same languages. Drupal will make a best effort to determine the correct language based on the code that the browser sends, but for finer control you can add and edit mappings from browser language codes to the <a href="@configure-languages">languages used by Drupal</a>.', array('@configure-languages' => url('admin/config/regional/language'))) . '</p>';
       return $output;
 
     case 'admin/config/regional/language/detection/selected':
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php
index 5571668..1dfa3bb 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php
@@ -151,8 +151,6 @@ function testLanguageFromBrowser() {
       'zh-mo' => 'zh-hant',
       'zh-hans' => 'zh-hans',
       'zh-hant' => 'zh-hant',
-      'zh-chs' => 'zh-hans',
-      'zh-cht' => 'zh-hant',
     );
 
     $mappings = $this->container->get('config.factory')->get('language.mappings')->get();
