diff --git a/core/modules/language/language.admin.inc b/core/modules/language/language.admin.inc
index 79dc5d1..8823b9e 100644
--- a/core/modules/language/language.admin.inc
+++ b/core/modules/language/language.admin.inc
@@ -8,6 +8,274 @@
 use Drupal\Core\Language\LanguageManager;
 
 /**
+ * User interface for the language overview screen.
+ */
+function language_admin_overview_form($form, &$form_state) {
+  drupal_static_reset('language_list');
+  $form_state['languages'] = $languages = language_list();
+  $form_state['language_default'] = $default = language_default();
+
+  $form['languages'] = array(
+    '#type' => 'table',
+    '#header' => array(
+      t('Name'),
+      t('Weight'),
+      t('Operations'),
+    ),
+    '#tabledrag' => array(
+      array('order', 'sibling', 'language-order-weight'),
+    ),
+  );
+
+  foreach ($languages as $langcode => $language) {
+    $form['languages'][$langcode]['#attributes']['class'][] = 'draggable';
+    $language->weight = $form_state['values']['languages'][$langcode]['weight'];
+    language_save($language);
+    $form['languages'][$langcode]['name'] = array(
+      '#markup' => check_plain($language->name),
+    );
+    $form['languages'][$langcode]['weight'] = array(
+      '#type' => 'weight',
+      '#title' => t('Weight for @title', array('@title' => $language->name)),
+      '#title_display' => 'invisible',
+      '#default_value' => $language->weight,
+      '#attributes' => array(
+        'class' => array('language-order-weight'),
+      ),
+      '#delta' => 30,
+    );
+    $links = array();
+    $links['edit'] = array(
+      'title' => t('edit'),
+      'href' => 'admin/config/regional/language/edit/' . $langcode,
+    );
+    if ($langcode != $default->langcode) {
+      $links['delete'] = array(
+        'title' => t('delete'),
+        'href' => 'admin/config/regional/language/delete/' . $langcode,
+      );
+    }
+    $form['languages'][$langcode]['operations'] = array(
+      '#type' => 'operations',
+      '#links' => $links,
+      '#weight' => 100,
+    );
+  drupal_set_message(t('Configuration saved.'));
+  }
+
+  $form['actions'] = array('#type' => 'actions');
+  $form['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save configuration'),
+  );
+
+  return $form;
+}
+
+ * User interface for the language addition screen.
+ */
+function language_admin_add_form($form, &$form_state) {
+  $predefined_languages = language_admin_predefined_list();
+  $predefined_languages['custom'] = t('Custom language...');
+  $predefined_default = !empty($form_state['values']['predefined_langcode']) ? $form_state['values']['predefined_langcode'] : key($predefined_languages);
+  $form['predefined_langcode'] = array(
+    '#type' => 'select',
+    '#title' => t('Language name'),
+    '#default_value' => $predefined_default,
+    '#options' => $predefined_languages,
+  );
+  $form['predefined_submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Add language'),
+    '#limit_validation_errors' => array(array('predefined_langcode'), array('predefined_submit')),
+    '#states' => array(
+      'invisible' => array(
+        'select#edit-predefined-langcode' => array('value' => 'custom'),
+      ),
+    ),
+    '#validate' => array('language_admin_add_predefined_form_validate'),
+    '#submit' => array('language_admin_add_form_submit'),
+  );
+
+  $form['custom_language'] = array(
+    '#type' => 'container',
+    '#states' => array(
+      'visible' => array(
+        'select#edit-predefined-langcode' => array('value' => 'custom'),
+      ),
+    ),
+  );
+  _language_admin_common_controls($form['custom_language']);
+  $form['custom_language']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Add custom language'),
+    '#validate' => array('language_admin_add_custom_form_validate'),
+    '#submit' => array('language_admin_add_form_submit'),
+  );
+
+  return $form;
+}
+
+/**
+ * Editing screen for a particular language.
+ *
+ * @param $langcode
+ *   Language code of the language to edit.
+ */
+function language_admin_edit_form($form, &$form_state, $language) {
+  _language_admin_common_controls($form, $language);
+  $form['actions'] = array('#type' => 'actions');
+  $form['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save language')
+  );
+  $form['#submit'][] = 'language_admin_edit_form_submit';
+  $form['#validate'][] = 'language_admin_edit_form_validate';
+  return $form;
+}
+
+/**
+ * Common elements of the language addition and editing form.
+ *
+ * @param $form
+ *   A parent form item (or empty array) to add items below.
+ * @param $language
+ *   Language object to edit.
+ */
+function _language_admin_common_controls(&$form, $language = NULL) {
+  if (!is_object($language)) {
+    $language = new Language(array('id' => NULL, 'name' => NULL,));
+  }
+  if (isset($language->id)) {
+    $form['langcode_view'] = array(
+      '#type' => 'item',
+      '#title' => t('Language code'),
+      '#markup' => $language->id
+    );
+    $form['langcode'] = array(
+      '#type' => 'value',
+      '#value' => $language->id
+    );
+  }
+  else {
+    $form['langcode'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Language code'),
+      '#maxlength' => 12,
+      '#required' => TRUE,
+      '#default_value' => '',
+      '#disabled' => FALSE,
+      '#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/')),
+    );
+  }
+  $form['name'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Language name in English'),
+    '#maxlength' => 64,
+    '#default_value' => @$language->name,
+    '#required' => TRUE,
+  );
+  $form['direction'] = array(
+    '#type' => 'radios',
+    '#title' => t('Direction'),
+    '#required' => TRUE,
+    '#description' => t('Direction that text in this language is presented.'),
+    '#default_value' => @$language->direction,
+    '#options' => array(Language::DIRECTION_LTR => t('Left to right'), Language::DIRECTION_RTL => t('Right to left')),
+  );
+  return $form;
+}
+
+/**
+ * Element specific validator for the Add language button.
+ */
+function language_admin_add_predefined_form_validate($form, &$form_state) {
+  $langcode = $form_state['values']['predefined_langcode'];
+  if ($langcode == 'custom') {
+    form_set_error('predefined_langcode', t('Fill in the language details and save the language with <em>Add custom language</em>.'));
+  }
+  else {
+    if ($language = language_load($langcode)) {
+      form_set_error('predefined_langcode', t('The language %language (%langcode) already exists.', array('%language' => $language->name, '%langcode' => $langcode)));
+    }
+  }
+}
+
+/**
+ * Validate the language addition form on custom language button.
+ */
+function language_admin_add_custom_form_validate($form, &$form_state) {
+  if ($form_state['values']['predefined_langcode'] == 'custom') {
+    $langcode = $form_state['values']['langcode'];
+    // Reuse the editing form validation routine if we add a custom language.
+    language_admin_edit_form_validate($form['custom_language'], $form_state);
+
+    if ($language = language_load($langcode)) {
+      form_set_error('langcode', t('The language %language (%langcode) already exists.', array('%language' => $language->name, '%langcode' => $langcode)));
+    }
+  }
+  else {
+    form_set_error('predefined_langcode', t('Use the <em>Add language</em> button to save a predefined language.'));
+  }
+}
+
+/**
+ * Process the custom and predefined language addition form submission.
+ */
+function language_admin_add_form_submit($form, &$form_state) {
+  $langcode = $form_state['values']['predefined_langcode'];
+  if ($langcode == 'custom') {
+    $langcode = $form_state['values']['langcode'];
+    // Custom language form.
+    $language = new Language(array(
+      'id' => $langcode,
+      'name' => $form_state['values']['name'],
+      'direction' => $form_state['values']['direction'],
+    ));
+  }
+  else {
+    $language = new Language(array('id' => $langcode));
+  }
+  // Save the language and inform the user that it happened.
+  $language = language_save($language);
+  drupal_set_message(t('The language %language has been created and can now be used.', array('%language' => $language->name)));
+
+  // Tell the user they have the option to add a language switcher block
+  // to their theme so they can switch between the languages.
+  drupal_set_message(t('Use one of the language switcher blocks to allow site visitors to switch between languages. You can enable these blocks on the <a href="@block-admin">block administration page</a>.', array('@block-admin' => url('admin/structure/block'))));
+
+  $form_state['redirect'] = 'admin/config/regional/language';
+}
+
+/**
+ * Validate the language editing form. Reused for custom language addition too.
+ */
+function language_admin_edit_form_validate($form, &$form_state) {
+  // Ensure sane field values for langcode and name.
+  if (!isset($form['langcode_view']) && preg_match('@[^a-zA-Z_-]@', $form_state['values']['langcode'])) {
+    form_set_error('langcode', t('%field may only contain characters a-z, underscores, or hyphens.', array('%field' => $form['langcode']['#title'])));
+  }
+  if ($form_state['values']['name'] != check_plain($form_state['values']['name'])) {
+    form_set_error('name', t('%field cannot contain any markup.', array('%field' => $form['name']['#title'])));
+  }
+}
+
+/**
+ * Process the language editing form submission.
+ */
+function language_admin_edit_form_submit($form, &$form_state) {
+  // Prepare a language object for saving.
+  $languages = language_list();
+  $langcode = $form_state['values']['langcode'];
+  $language = $languages[$langcode];
+  $language->name = $form_state['values']['name'];
+  $language->direction = $form_state['values']['direction'];
+  language_save($language);
+  $form_state['redirect'] = 'admin/config/regional/language';
+}
+
+
+/**
  * Prepare a language code list for unused predefined languages.
  */
 function language_admin_predefined_list() {
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 3c5dfed..43346e4 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -694,7 +694,7 @@ function locale_library_info_alter(&$libraries, $module) {
  * Implements hook_form_FORM_ID_alter() for language_admin_overview_form().
  */
 function locale_form_language_admin_overview_form_alter(&$form, &$form_state) {
-  $languages = $form['languages']['#languages'];
+  $languages = $form_state['languages'];
 
   $total_strings = \Drupal::service('locale.storage')->countStrings();
   $stats = array_fill_keys(array_keys($languages), array());
