diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index e5b1829..a6571d5 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -2653,7 +2653,7 @@ function language_list($field = 'language') {
   if (!isset($languages)) {
     $default = language_default();
     if (drupal_multilingual() || module_exists('locale')) {
-      $languages['language'] = db_query('SELECT * FROM {languages} ORDER BY weight ASC, name ASC')->fetchAllAssoc('language');
+      $languages['language'] = db_query('SELECT * FROM {language} ORDER BY weight ASC, name ASC')->fetchAllAssoc('language');
     }
     else {
       // No locale module, so use the default language only.
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index f9d8062..5e4dfec 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -1146,7 +1146,7 @@ function install_find_translations() {
   foreach ($files as $key => $file) {
     // Strip off the file name component before the language code.
     $files[$key]->langcode = preg_replace('!^(.+\.)?([^\.]+)$!', '\2', $file->name);
-    // Language codes cannot exceed 12 characters to fit into the {languages}
+    // Language codes cannot exceed 12 characters to fit into the {language}
     // table.
     if (strlen($files[$key]->langcode) > 12) {
       unset($files[$key]);
@@ -1432,7 +1432,7 @@ function install_import_translations(&$install_state) {
       'name' => $langcode,
       'default' => TRUE,
     );
-    locale_language_save($language);
+    language_save($language);
   }
   else {
     // A known predefined language, details will be filled in properly.
@@ -1440,7 +1440,7 @@ function install_import_translations(&$install_state) {
       'language' => $langcode,
       'default' => TRUE,
     );
-    locale_language_save($language);
+    language_save($language);
   }
 
   // Collect files to import for this language.
diff --git a/core/includes/locale.inc b/core/includes/locale.inc
index 85d2a8b..da082c3 100644
--- a/core/includes/locale.inc
+++ b/core/includes/locale.inc
@@ -535,63 +535,6 @@ function locale_string_is_safe($string) {
 }
 
 /**
- * API function to add or update a language.
- *
- * @param $language
- *   Language object with properties corresponding to 'languages' table columns.
- */
-function locale_language_save($language) {
-  $language->is_new = !(bool) db_query_range('SELECT 1 FROM {languages} WHERE language = :language', 0, 1, array(':language' => $language->language))->fetchField();
-
-  // If name was not set, we add a predefined language.
-  if (!isset($language->name)) {
-    include_once DRUPAL_ROOT . '/core/includes/standard.inc';
-    $predefined = standard_language_list();
-    $language->name = $predefined[$language->language][0];
-    $language->direction = isset($predefined[$language->language][2]) ? $predefined[$language->language][2] : LANGUAGE_LTR;
-  }
-
-  // Set to enabled for the default language and unless specified otherwise.
-  if (!empty($language->default) || !isset($language->enabled)) {
-    $language->enabled = TRUE;
-  }
-  // Let other modules modify $language before saved.
-  module_invoke_all('locale_language_presave', $language);
-
-  // Save the record and inform others about the change.
-  if ($language->is_new) {
-    drupal_write_record('languages', $language);
-    module_invoke_all('locale_language_insert', $language);
-    watchdog('locale', 'The %language (%langcode) language has been created.', array('%language' => $language->name, '%langcode' => $language->language));
-  }
-  else {
-    drupal_write_record('languages', $language, array('language'));
-    module_invoke_all('locale_language_update', $language);
-    watchdog('locale', 'The %language (%langcode) language has been updated.', array('%language' => $language->name, '%langcode' => $language->language));
-  }
-
-  if (!empty($language->default)) {
-    // Set the new version of this language as default in a variable.
-    $default_language = language_default();
-    variable_set('language_default', $language);
-  }
-
-  // Update language count based on enabled language count.
-  variable_set('language_count', db_query('SELECT COUNT(language) FROM {languages} WHERE enabled = 1')->fetchField());
-
-  // Kill the static cache in language_list().
-  drupal_static_reset('language_list');
-
-  // @todo move these two cache clears out. See http://drupal.org/node/1293252
-  // Changing the language settings impacts the interface.
-  cache_clear_all('*', 'cache_page', TRUE);
-  // Force JavaScript translation file re-creation for the modified language.
-  _locale_invalidate_js($language->language);
-
-  return $language;
-}
-
-/**
  * Parses a JavaScript file, extracts strings wrapped in Drupal.t() and
  * Drupal.formatPlural() and inserts them into the database.
  */
@@ -866,34 +809,6 @@ function _locale_rebuild_js($langcode = NULL) {
 }
 
 /**
- * @defgroup locale-api-predefined List of predefined languages
- * @{
- * API to provide a list of predefined languages.
- */
-
-/**
- * Prepares the language code list for a select form item with only the unsupported ones
- */
-function _locale_prepare_predefined_list() {
-  include_once DRUPAL_ROOT . '/core/includes/standard.inc';
-  $languages = language_list();
-  $predefined = standard_language_list();
-  foreach ($predefined as $key => $value) {
-    if (isset($languages[$key])) {
-      unset($predefined[$key]);
-      continue;
-    }
-    $predefined[$key] = t($value[0]);
-  }
-  asort($predefined);
-  return $predefined;
-}
-
-/**
- * @} End of "locale-api-languages-predefined"
- */
-
-/**
  * Get list of all predefined and custom countries.
  *
  * @return
diff --git a/core/includes/update.inc b/core/includes/update.inc
index 5c67611..b5c6aa1 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -100,6 +100,9 @@ function update_prepare_d8_bootstrap() {
         'description' => $has_required_schema ? '' : 'Please update your Drupal 7 installation to the most recent version before attempting to upgrade to Drupal 8',
       ),
     );
+    if ($has_required_schema) {
+      db_rename_table('languages', 'language');
+    }
   }
 }
 
diff --git a/core/modules/comment/comment.install b/core/modules/comment/comment.install
index 0213808..9c4a2d8 100644
--- a/core/modules/comment/comment.install
+++ b/core/modules/comment/comment.install
@@ -168,7 +168,7 @@ function comment_schema() {
         'description' => "The comment author's home page address from the comment form, if user is anonymous, and the 'Anonymous users may/must leave their contact information' setting is turned on.",
       ),
       'language' => array(
-        'description' => 'The {languages}.language of this comment.',
+        'description' => 'The {language}.language of this comment.',
         'type' => 'varchar',
         'length' => 12,
         'not null' => TRUE,
diff --git a/core/modules/field/field.multilingual.inc b/core/modules/field/field.multilingual.inc
index 4497074..4b0b1d9 100644
--- a/core/modules/field/field.multilingual.inc
+++ b/core/modules/field/field.multilingual.inc
@@ -60,23 +60,23 @@
  */
 
 /**
- * Implements hook_locale_language_insert().
+ * Implements hook_language_insert().
  */
-function field_locale_language_insert() {
+function field_language_insert() {
   field_info_cache_clear();
 }
 
 /**
- * Implements hook_locale_language_update().
+ * Implements hook_language_update().
  */
-function field_locale_language_update() {
+function field_language_update() {
   field_info_cache_clear();
 }
 
 /**
- * Implements hook_locale_language_delete().
+ * Implements hook_language_delete().
  */
-function field_locale_language_delete() {
+function field_language_delete() {
   field_info_cache_clear();
 }
 
diff --git a/core/modules/field/tests/field.test b/core/modules/field/tests/field.test
index 214eab4..667bac1 100644
--- a/core/modules/field/tests/field.test
+++ b/core/modules/field/tests/field.test
@@ -2648,7 +2648,7 @@ class FieldTranslationsTestCase extends FieldTestCase {
         'language' => 'l' . $i,
         'name' => $this->randomString(),
       );
-      locale_language_save($language);
+      language_save($language);
     }
   }
 
diff --git a/core/modules/language/language.admin.inc b/core/modules/language/language.admin.inc
new file mode 100644
index 0000000..9e64f57
--- /dev/null
+++ b/core/modules/language/language.admin.inc
@@ -0,0 +1,438 @@
+<?php
+
+/**
+ * @file
+ * Administration functions for language.module.
+ */
+
+/**
+ * User interface for the language overview screen.
+ */
+function language_admin_overview_form($form, &$form_state) {
+  drupal_static_reset('language_list');
+  $languages = language_list('language');
+  $default = language_default();
+
+  $form['languages'] = array(
+    '#languages' => $languages,
+    '#language_default' => $default,
+    '#tree' => TRUE,
+    '#header' => array(
+      t('Name'),
+      t('Enabled'),
+      t('Default'),
+      t('Weight'),
+      t('Operations'),
+    ),
+    '#theme' => 'language_admin_overview_form_table',
+  );
+
+  foreach ($languages as $langcode => $language) {
+    $form['languages'][$langcode]['#weight'] = $language->weight;
+    $form['languages'][$langcode]['name'] = array(
+      '#markup' => check_plain($language->name),
+    );
+    $form['languages'][$langcode]['enabled'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Enable @title', array('@title' => $language->name)),
+      '#title_display' => 'invisible',
+      '#default_value' => (int) $language->enabled,
+      '#disabled' => $langcode == $default->language,
+    );
+    $form['languages'][$langcode]['default'] = array(
+      '#type' => 'radio',
+      '#parents' => array('site_default'),
+      '#title' => t('Set @title as default', array('@title' => $language->name)),
+      '#title_display' => 'invisible',
+      '#return_value' => $langcode,
+      '#default_value' => ($langcode == $default->language ? $langcode : NULL),
+      '#id' => 'edit-site-default-' . $langcode,
+    );
+    $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'),
+      ),
+    );
+    $form['languages'][$langcode]['operations'] = array(
+      '#theme_wrappers' => array('language_admin_operations'),
+      '#weight' => 100,
+    );
+    $form['languages'][$langcode]['operations']['edit'] = array(
+      '#type' => 'link',
+      '#title' => t('edit'),
+      '#href' => 'admin/config/regional/language/edit/' . $langcode,
+    );
+    $form['languages'][$langcode]['operations']['delete'] = array(
+      '#type' => 'link',
+      '#title' => t('delete'),
+      '#href' => 'admin/config/regional/language/delete/' . $langcode,
+      '#access' => $langcode != $default->language,
+    );
+  }
+
+  $form['actions'] = array('#type' => 'actions');
+  $form['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save configuration'),
+  );
+
+  return $form;
+}
+
+/**
+ * Returns HTML for operation links in language_admin_overview_form() table.
+ *
+ * @todo Introduce #type '[table_]operations' or just simply #type 'links'.
+ */
+function theme_language_admin_operations($variables) {
+  $links = array();
+  foreach (element_children($variables['elements']) as $key) {
+    // Children are only rendered if the current user has access.
+    if (isset($variables['elements'][$key]['#children'])) {
+      $links[$key] = $variables['elements'][$key]['#children'];
+    }
+  }
+  // If there are links, render a link list.
+  if (!empty($links)) {
+    return theme('item_list__operations', array(
+      'items' => $links,
+      'attributes' => array('class' => array('links', 'inline')),
+    ));
+  }
+  // Otherwise, ensure to produce no output.
+  return '';
+}
+
+/**
+ * Returns HTML for the language overview form.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - form: A render element representing the form.
+ *
+ * @ingroup themeable
+ */
+function theme_language_admin_overview_form_table($variables) {
+  $form = $variables['form'];
+
+  $rows = array();
+  foreach (element_children($form, TRUE) as $langcode) {
+    $element = &$form[$langcode];
+    $row = array(
+      'class' => array('draggable'),
+    );
+    foreach (element_children($element, TRUE) as $column) {
+      $cell = &$element[$column];
+      $row['data'][] = drupal_render($cell);
+    }
+    $rows[] = $row;
+  }
+
+  $output = theme('table', array(
+    'header' => $form['#header'],
+    'rows' => $rows,
+    'attributes' => array('id' => 'language-order'),
+  ));
+  $output .= drupal_render_children($form);
+
+  drupal_add_tabledrag('language-order', 'order', 'sibling', 'language-order-weight');
+
+  return $output;
+}
+
+/**
+ * Process language overview form submissions, updating existing languages.
+ */
+function language_admin_overview_form_submit($form, &$form_state) {
+  $languages = language_list();
+  $old_default = language_default();
+
+  foreach ($languages as $langcode => $language) {
+    $language->default = ($form_state['values']['site_default'] == $langcode);
+    $language->weight = $form_state['values']['languages'][$langcode]['weight'];
+
+    if ($language->default || $old_default->language == $langcode) {
+      // Automatically enable the default language and the language
+      // which was default previously (because we will not get the
+      // value from that disabled checkbox).
+      $form_state['values']['languages'][$langcode]['enabled'] = 1;
+    }
+    $language->enabled = (int) !empty($form_state['values']['languages'][$langcode]['enabled']);
+
+    language_save($language);
+  }
+
+  drupal_set_message(t('Configuration saved.'));
+}
+
+/**
+ * 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_predefined_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_custom_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 stdClass();
+  }
+  if (isset($language->language)) {
+    $form['langcode_view'] = array(
+      '#type' => 'item',
+      '#title' => t('Language code'),
+      '#markup' => $language->language
+    );
+    $form['langcode'] = array(
+      '#type' => 'value',
+      '#value' => $language->language
+    );
+  }
+  else {
+    $form['langcode'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Language code'),
+      '#maxlength' => 12,
+      '#required' => TRUE,
+      '#default_value' => @$language->language,
+      '#disabled' => (isset($language->language)),
+      '#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'),
+    '#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_LTR => t('Left to right'), LANGUAGE_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_load($langcode)) {
+      form_set_error('predefined_langcode', t('The language %language (%langcode) already exists.', array('%language' => $languages[$langcode]->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, $form_state);
+
+    $languages = language_list();
+    if (isset($languages[$langcode])) {
+     form_set_error('langcode', t('The language %language (%langcode) already exists.', array('%language' => $languages[$langcode]->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 language addition form submission.
+ */
+function language_admin_add_custom_form_submit($form, &$form_state) {
+  $langcode = $form_state['values']['langcode'];
+  // Custom language form.
+  $language = (object) array(
+    'language' => $langcode,
+    'name' => $form_state['values']['name'],
+    'direction' => $form_state['values']['direction'],
+  );
+  language_save($language);
+  drupal_set_message(t('The language %language has been created and can now be used.', array('%language' => $form_state['values']['name'])));
+  $form_state['redirect'] = 'admin/config/regional/language';
+}
+
+/**
+ * Process the predefined language addition form submission.
+ */
+function language_admin_add_predefined_form_submit($form, &$form_state) {
+  // Predefined language selection.
+  $langcode = $form_state['values']['predefined_langcode'];
+  include_once DRUPAL_ROOT . '/core/includes/standard.inc';
+  $predefined = standard_language_list();
+  $language = (object) array(
+    'language' => $langcode,
+  );
+  language_save($language);
+  drupal_set_message(t('The language %language has been created and can now be used.', array('%language' => t($predefined[$langcode][0]))));
+  $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';
+}
+
+/**
+ * User interface for the language deletion confirmation screen.
+ */
+function language_admin_delete_form($form, &$form_state, $language) {
+  $langcode = $language->language;
+
+  if (language_default()->language == $langcode) {
+    drupal_set_message(t('The default language cannot be deleted.'));
+    drupal_goto('admin/config/regional/language');
+  }
+
+  // For other languages, warn user that data loss is ahead.
+  $languages = language_list();
+
+  if (!isset($languages[$langcode])) {
+    drupal_not_found();
+    drupal_exit();
+  }
+  else {
+    $form['langcode'] = array('#type' => 'value', '#value' => $langcode);
+    return confirm_form($form, t('Are you sure you want to delete the language %language?', array('%language' => $languages[$langcode]->name)), 'admin/config/regional/language', t('Deleting a language will remove all interface translations associated with it, and posts in this language will be set to be language neutral. This action cannot be undone.'), t('Delete'), t('Cancel'));
+  }
+}
+
+/**
+ * Process language deletion submissions.
+ */
+function language_admin_delete_form_submit($form, &$form_state) {
+  $langcode = $form_state['values']['langcode'];
+  $languages = language_list();
+  $language = $languages[$langcode];
+
+  $success = language_delete($langcode);
+
+  if ($success) {
+    $t_args = array('%language' => $language->name, '%langcode' => $language->language);
+    drupal_set_message(t('The %language (%langcode) language has been removed.', $t_args));
+  }
+
+  $form_state['redirect'] = 'admin/config/regional/language';
+}
+
+/**
+ * Prepare language code list for unused predefined languages.
+ */
+function language_admin_predefined_list() {
+  include_once DRUPAL_ROOT . '/core/includes/standard.inc';
+  $languages = language_list();
+  $predefined = standard_language_list();
+  foreach ($predefined as $key => $value) {
+    if (isset($languages[$key])) {
+      unset($predefined[$key]);
+      continue;
+    }
+    $predefined[$key] = t($value[0]);
+  }
+  asort($predefined);
+  return $predefined;
+}
diff --git a/core/modules/language/language.api.php b/core/modules/language/language.api.php
new file mode 100644
index 0000000..08ff994
--- /dev/null
+++ b/core/modules/language/language.api.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Hooks provided by the Language module.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+ /**
+ * React to a language about to be added or updated in the system.
+ *
+ * @param $language
+ *   A language object.
+ */
+function hook_language_presave($language) {
+  if ($language->default) {
+    // React to a new default language.
+    example_new_default_language($language);
+  }
+}
+
+/**
+ * React to a language that was just added to the system.
+ *
+ * @param $language
+ *   A language object.
+ */
+function hook_language_insert($language) {
+  example_refresh_permissions();
+}
+
+/**
+ * React to a language that was just updated in the system.
+ *
+ * @param $language
+ *   A language object.
+ */
+function hook_language_update($language) {
+  example_refresh_permissions();
+}
+
+/**
+ * Allow modules to react before the deletion of a language.
+ *
+ * @param $language
+ *   The language object of the language that is about to be deleted.
+ */
+function hook_language_delete($language) {
+  // On nodes with this language, unset the language
+  db_update('node')
+    ->fields(array('language' => ''))
+    ->condition('language', $language->language)
+    ->execute();
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */
diff --git a/core/modules/language/language.info b/core/modules/language/language.info
new file mode 100644
index 0000000..edf37b9
--- /dev/null
+++ b/core/modules/language/language.info
@@ -0,0 +1,6 @@
+name = Language
+description = Lets you configure a number of languages to be used on your website.
+package = Core
+version = VERSION
+core = 8.x
+configure = admin/config/regional/language
diff --git a/core/modules/language/language.install b/core/modules/language/language.install
new file mode 100644
index 0000000..4ba83d6
--- /dev/null
+++ b/core/modules/language/language.install
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the language module.
+ */
+
+/**
+ * Implements hook_install().
+ */
+function language_install() {
+  // Add the default language to the database too.
+  language_save(language_default());
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function language_uninstall() {
+  // Clear variables.
+  variable_del('language_default');
+  variable_del('language_count');
+
+  // Re-initialize the language system so successive calls to t() and other
+  // functions will not expect languages to be present.
+  drupal_language_initialize();
+}
+
+/**
+ * Implements hook_schema().
+ */
+function language_schema() {
+  $schema['language'] = array(
+    'description' => 'List of all available languages in the system.',
+    'fields' => array(
+      'language' => array(
+        'type' => 'varchar',
+        'length' => 12,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => "Language code, e.g. 'de' or 'en-US'.",
+      ),
+      'name' => array(
+        'type' => 'varchar',
+        'length' => 64,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'Language name.',
+      ),
+      'direction' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'Direction of language (Left-to-Right = 0, Right-to-Left = 1).',
+      ),
+      'enabled' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'Enabled flag (1 = Enabled, 0 = Disabled).',
+      ),
+      'weight' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'Weight, used in lists of languages.',
+      ),
+    ),
+    'primary key' => array('language'),
+    'indexes' => array(
+      'list' => array('weight', 'name'),
+    ),
+  );
+  return $schema;
+}
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
new file mode 100644
index 0000000..1364d69
--- /dev/null
+++ b/core/modules/language/language.module
@@ -0,0 +1,189 @@
+<?php
+
+/**
+ * @file
+ *   Add language handling functionality to Drupal.
+ */
+
+/**
+ * Implements hook_help().
+ */
+function language_help($path, $arg) {
+  switch ($path) {
+    case 'admin/config/regional/language':
+      return '<p>' . t('With multiple languages enabled, registered users may select their preferred language and authors can assign a specific language to content.') . '</p>';
+
+    case 'admin/config/regional/language/add':
+      return '<p>' . t('Add a language to be supported by your site. If your desired language is not available, pick <em>Custom language...</em> at the end and provide a language code and other details manually.') . '</p>';
+  }
+}
+
+/**
+ * Implements hook_menu().
+ */
+function language_menu() {
+  $items['admin/config/regional/language'] = array(
+    'title' => 'Languages',
+    'description' => 'Configure languages for content and the user interface.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('language_admin_overview_form'),
+    'access arguments' => array('administer languages'),
+    'file' => 'language.admin.inc',
+    'weight' => -10,
+  );
+  $items['admin/config/regional/language/overview'] = array(
+    'title' => 'List',
+    'weight' => 0,
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+  );
+  $items['admin/config/regional/language/add'] = array(
+    'title' => 'Add language',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('language_admin_add_form'),
+    'access arguments' => array('administer languages'),
+    'weight' => 5,
+    'type' => MENU_LOCAL_ACTION,
+    'file' => 'language.admin.inc',
+  );
+  $items['admin/config/regional/language/edit/%language'] = array(
+    'title' => 'Edit language',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('language_admin_edit_form', 5),
+    'access arguments' => array('administer languages'),
+    'file' => 'language.admin.inc',
+  );
+  $items['admin/config/regional/language/delete/%language'] = array(
+    'title' => 'Confirm delete',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('language_admin_delete_form', 5),
+    'access arguments' => array('administer languages'),
+    'file' => 'language.admin.inc',
+  );
+  return $items;
+}
+
+/**
+ * Implements hook_permission().
+ */
+function language_permission() {
+  return array(
+    'administer languages' => array(
+      'title' => t('Administer languages'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_theme().
+ */
+function language_theme() {
+  return array(
+    'language_admin_overview_form_table' => array(
+      'render element' => 'form',
+      'file' => 'language.admin.inc',
+    ),
+    'language_admin_operations' => array(
+      'render element' => 'elements',
+      'file' => 'language.admin.inc',
+    ),
+  );
+}
+
+/**
+ * Loads a language object from the database.
+ *
+ * @param $langcode
+ *   The language code.
+ *
+ * @return
+ *   A fully-populated language object or FALSE.
+ */
+function language_load($langcode) {
+  $languages = language_list();
+  return isset($languages[$langcode]) ? $languages[$langcode] : FALSE;
+}
+
+/**
+ * API function to add or update a language.
+ *
+ * @param $language
+ *   Language object with properties corresponding to 'language' table columns.
+ */
+function language_save($language) {
+  $language->is_new = !(bool) db_query_range('SELECT 1 FROM {language} WHERE language = :language', 0, 1, array(':language' => $language->language))->fetchField();
+
+  // If name was not set, we add a predefined language.
+  if (!isset($language->name)) {
+    include_once DRUPAL_ROOT . '/core/includes/standard.inc';
+    $predefined = standard_language_list();
+    $language->name = $predefined[$language->language][0];
+    $language->direction = isset($predefined[$language->language][2]) ? $predefined[$language->language][2] : LANGUAGE_LTR;
+  }
+
+  // Set to enabled for the default language and unless specified otherwise.
+  if (!empty($language->default) || !isset($language->enabled)) {
+    $language->enabled = TRUE;
+  }
+  // Let other modules modify $language before saved.
+  module_invoke_all('language_presave', $language);
+
+  // Save the record and inform others about the change.
+  $t_args = array('%language' => $language->name, '%langcode' => $language->language);
+  if ($language->is_new) {
+    drupal_write_record('language', $language);
+    module_invoke_all('language_insert', $language);
+    watchdog('language', 'The %language (%langcode) language has been created.', $t_args);
+  }
+  else {
+    drupal_write_record('language', $language, array('language'));
+    module_invoke_all('language_update', $language);
+    watchdog('language', 'The %language (%langcode) language has been updated.', $t_args);
+  }
+
+  if (!empty($language->default)) {
+    // Set the new version of this language as default in a variable.
+    $default_language = language_default();
+    variable_set('language_default', $language);
+  }
+
+  // Update language count based on enabled language count.
+  variable_set('language_count', db_query('SELECT COUNT(language) FROM {language} WHERE enabled = 1')->fetchField());
+
+  // Kill the static cache in language_list().
+  drupal_static_reset('language_list');
+
+  return $language;
+}
+
+/**
+ * Delete a language.
+ *
+ * @param $langcode
+ *   Language code of the language to be deleted.
+ * @return
+ *   TRUE if language is successfully deleted. Otherwise FALSE.
+ */
+function language_delete($langcode) {
+  $languages = language_list();
+  if (isset($languages[$langcode])) {
+    $language = $languages[$langcode];
+
+    module_invoke_all('language_delete', $language);
+
+    // Remove the language.
+    db_delete('language')
+      ->condition('language', $language->language)
+      ->execute();
+
+    if ($language->enabled) {
+      variable_set('language_count', variable_get('language_count', 1) - 1);
+    }
+
+    drupal_static_reset('language_list');
+
+    $t_args = array('%language' => $language->name, '%langcode' => $language->language);
+    watchdog('language', 'The %language (%langcode) language has been removed.', $t_args);
+    return TRUE;
+  }
+  return FALSE;
+}
diff --git a/core/modules/locale/locale.admin.inc b/core/modules/locale/locale.admin.inc
index 5732697..775ba1b 100644
--- a/core/modules/locale/locale.admin.inc
+++ b/core/modules/locale/locale.admin.inc
@@ -6,444 +6,6 @@
  */
 
 /**
- * @defgroup locale-language-administration Language administration interface
- * @{
- * Administration interface for languages.
- *
- * These functions provide the user interface to show, add, edit and
- * delete languages as well as providing options for language negotiation.
- */
-
-/**
- * User interface for the language overview screen.
- */
-function locale_language_overview_form($form, &$form_state) {
-  drupal_static_reset('language');
-  $languages = language_list('language');
-  $default = language_default();
-
-  $form['languages'] = array(
-    '#languages' => $languages,
-    '#language_default' => $default,
-    '#tree' => TRUE,
-    '#header' => array(
-      t('Name'),
-      t('Enabled'),
-      t('Default'),
-      t('Weight'),
-      t('Operations'),
-    ),
-    '#theme' => 'locale_language_overview_form_table',
-  );
-
-  foreach ($languages as $langcode => $language) {
-    $form['languages'][$langcode]['#weight'] = $language->weight;
-    $form['languages'][$langcode]['name'] = array(
-      '#markup' => check_plain($language->name),
-    );
-    $form['languages'][$langcode]['enabled'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Enable @title', array('@title' => $language->name)),
-      '#title_display' => 'invisible',
-      '#default_value' => (int) $language->enabled,
-      '#disabled' => $langcode == $default->language,
-    );
-    $form['languages'][$langcode]['default'] = array(
-      '#type' => 'radio',
-      '#parents' => array('site_default'),
-      '#title' => t('Set @title as default', array('@title' => $language->name)),
-      '#title_display' => 'invisible',
-      '#return_value' => $langcode,
-      '#default_value' => ($langcode == $default->language ? $langcode : NULL),
-      '#id' => 'edit-site-default-' . $langcode,
-    );
-    $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'),
-      ),
-    );
-    $form['languages'][$langcode]['operations'] = array(
-      '#theme_wrappers' => array('locale_language_operations'),
-      '#weight' => 100,
-    );
-    $form['languages'][$langcode]['operations']['edit'] = array(
-      '#type' => 'link',
-      '#title' => t('edit'),
-      '#href' => 'admin/config/regional/language/edit/' . $langcode,
-    );
-    $form['languages'][$langcode]['operations']['delete'] = array(
-      '#type' => 'link',
-      '#title' => t('delete'),
-      '#href' => 'admin/config/regional/language/delete/' . $langcode,
-      '#access' => $langcode != $default->language,
-    );
-  }
-
-  $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Save configuration'),
-  );
-
-  return $form;
-}
-
-/**
- * Returns HTML for operation links in locale_language_overview_form() table.
- *
- * @todo Introduce #type '[table_]operations' or just simply #type 'links'.
- */
-function theme_locale_language_operations($variables) {
-  $links = array();
-  foreach (element_children($variables['elements']) as $key) {
-    // Children are only rendered if the current user has access.
-    if (isset($variables['elements'][$key]['#children'])) {
-      $links[$key] = $variables['elements'][$key]['#children'];
-    }
-  }
-  // If there are links, render a link list.
-  if (!empty($links)) {
-    return theme('item_list__operations', array(
-      'items' => $links,
-      'attributes' => array('class' => array('links', 'inline')),
-    ));
-  }
-  // Otherwise, ensure to produce no output.
-  return '';
-}
-
-/**
- * Returns HTML for the language overview form.
- *
- * @param $variables
- *   An associative array containing:
- *   - form: A render element representing the form.
- *
- * @ingroup themeable
- */
-function theme_locale_language_overview_form_table($variables) {
-  $form = $variables['form'];
-
-  $rows = array();
-  foreach (element_children($form, TRUE) as $langcode) {
-    $element = &$form[$langcode];
-    $row = array(
-      'class' => array('draggable'),
-    );
-    foreach (element_children($element, TRUE) as $column) {
-      $cell = &$element[$column];
-      $row['data'][] = drupal_render($cell);
-    }
-    $rows[] = $row;
-  }
-
-  $output = theme('table', array(
-    'header' => $form['#header'],
-    'rows' => $rows,
-    'attributes' => array('id' => 'language-order'),
-  ));
-  $output .= drupal_render_children($form);
-
-  drupal_add_tabledrag('language-order', 'order', 'sibling', 'language-order-weight');
-
-  return $output;
-}
-
-/**
- * Process language overview form submissions, updating existing languages.
- */
-function locale_language_overview_form_submit($form, &$form_state) {
-  $languages = language_list();
-  $old_default = language_default();
-  $url_prefixes = variable_get('locale_language_negotiation_url_part', LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX) == LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX;
-
-  foreach ($languages as $langcode => $language) {
-    $language->default = ($form_state['values']['site_default'] == $langcode);
-    $language->weight = $form_state['values']['languages'][$langcode]['weight'];
-
-    if ($language->default || $old_default->language == $langcode) {
-      // Automatically enable the default language and the language
-      // which was default previously (because we will not get the
-      // value from that disabled checkbox).
-      $form_state['values']['languages'][$langcode]['enabled'] = 1;
-    }
-    $language->enabled = (int) !empty($form_state['values']['languages'][$langcode]['enabled']);
-
-    locale_language_save($language);
-  }
-
-  drupal_set_message(t('Configuration saved.'));
-}
-
-/**
- * User interface for the language addition screen.
- */
-function locale_languages_add_form($form, &$form_state) {
-  $predefined_languages = _locale_prepare_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('locale_languages_add_predefined_form_validate'),
-    '#submit' => array('locale_languages_add_predefined_form_submit'),
-  );
-
-  $form['custom_language'] = array(
-    '#type' => 'container',
-    '#states' => array(
-      'visible' => array(
-        'select#edit-predefined-langcode' => array('value' => 'custom'),
-      ),
-    ),
-  );
-  _locale_languages_common_controls($form['custom_language']);
-  $form['custom_language']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Add custom language'),
-    '#validate' => array('locale_languages_add_custom_form_validate'),
-    '#submit' => array('locale_languages_add_custom_form_submit'),
-  );
-
-  return $form;
-}
-
-/**
- * Editing screen for a particular language.
- *
- * @param $langcode
- *   Language code of the language to edit.
- */
-function locale_languages_edit_form($form, &$form_state, $language) {
-  _locale_languages_common_controls($form, $language);
-  $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Save language')
-  );
-  $form['#submit'][] = 'locale_languages_edit_form_submit';
-  $form['#validate'][] = 'locale_languages_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 _locale_languages_common_controls(&$form, $language = NULL) {
-  if (!is_object($language)) {
-    $language = new stdClass();
-  }
-  if (isset($language->language)) {
-    $form['langcode_view'] = array(
-      '#type' => 'item',
-      '#title' => t('Language code'),
-      '#markup' => $language->language
-    );
-    $form['langcode'] = array(
-      '#type' => 'value',
-      '#value' => $language->language
-    );
-  }
-  else {
-    $form['langcode'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Language code'),
-      '#maxlength' => 12,
-      '#required' => TRUE,
-      '#default_value' => @$language->language,
-      '#disabled' => (isset($language->language)),
-      '#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'),
-    '#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_LTR => t('Left to right'), LANGUAGE_RTL => t('Right to left'))
-  );
-  return $form;
-}
-
-/**
- * Element specific validator for the Add language button.
- */
-function locale_languages_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_load($langcode)) {
-      form_set_error('predefined_langcode', t('The language %language (%code) already exists.', array('%language' => $languages[$langcode]->name, '%code' => $langcode)));
-    }
-  }
-}
-
-/**
- * Validate the language addition form on custom language button.
- */
-function locale_languages_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.
-    locale_languages_edit_form_validate($form, $form_state);
-
-    $languages = language_list();
-    if (isset($languages[$langcode])) {
-     form_set_error('langcode', t('The language %language (%code) already exists.', array('%language' => $languages[$langcode]->name, '%code' => $langcode)));
-    }
-  }
-  else {
-    form_set_error('predefined_langcode', t('Use the <em>Add language</em> button to save a predefined language.'));
-  }
-}
-
-/**
- * Process the custom language addition form submission.
- */
-function locale_languages_add_custom_form_submit($form, &$form_state) {
-  $langcode = $form_state['values']['langcode'];
-  // Custom language form.
-  $language = (object) array(
-    'language' => $langcode,
-    'name' => $form_state['values']['name'],
-    'direction' => $form_state['values']['direction'],
-  );
-  locale_language_save($language);
-  drupal_set_message(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array('%language' => $form_state['values']['name'], '@locale-help' => url('admin/help/locale'))));
-  locale_languages_add_set_batch($langcode);
-  $form_state['redirect'] = 'admin/config/regional/language';
-}
-
-/**
- * Process the predefined language addition form submission.
- */
-function locale_languages_add_predefined_form_submit($form, &$form_state) {
-  // Predefined language selection.
-  $langcode = $form_state['values']['predefined_langcode'];
-  include_once DRUPAL_ROOT . '/core/includes/standard.inc';
-  $predefined = standard_language_list();
-  $language = (object) array(
-    'language' => $langcode,
-  );
-  locale_language_save($language);
-  drupal_set_message(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array('%language' => t($predefined[$langcode][0]), '@locale-help' => url('admin/help/locale'))));
-  locale_languages_add_set_batch($langcode);
-  $form_state['redirect'] = 'admin/config/regional/language';
-}
-
-/**
- * Set a batch for newly added language.
- */
-function locale_languages_add_set_batch($langcode) {
-  // See if we have language files to import for the newly added
-  // language, collect and import them.
-  include_once drupal_get_path('module', 'locale') . '/locale.bulk.inc';
-  if ($batch = locale_translate_batch_import_files($langcode, TRUE)) {
-    batch_set($batch);
-  }
-}
-
-/**
- * Validate the language editing form. Reused for custom language addition too.
- */
-function locale_languages_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 locale_languages_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'];
-  locale_language_save($language);
-  $form_state['redirect'] = 'admin/config/regional/language';
-}
-
-/**
- * User interface for the language deletion confirmation screen.
- */
-function locale_languages_delete_form($form, &$form_state, $language) {
-  $langcode = $language->language;
-
-  if (language_default()->language == $langcode) {
-    drupal_set_message(t('The default language cannot be deleted.'));
-    drupal_goto('admin/config/regional/language');
-  }
-
-  // For other languages, warn user that data loss is ahead.
-  $languages = language_list();
-
-  if (!isset($languages[$langcode])) {
-    drupal_not_found();
-    drupal_exit();
-  }
-  else {
-    $form['langcode'] = array('#type' => 'value', '#value' => $langcode);
-    return confirm_form($form, t('Are you sure you want to delete the language %name?', array('%name' => $languages[$langcode]->name)), 'admin/config/regional/language', t('Deleting a language will remove all interface translations associated with it, and posts in this language will be set to be language neutral. This action cannot be undone.'), t('Delete'), t('Cancel'));
-  }
-}
-
-/**
- * Process language deletion submissions.
- */
-function locale_languages_delete_form_submit($form, &$form_state) {
-  $langcode = $form_state['values']['langcode'];
-  $languages = language_list();
-  $language = $languages[$langcode];
-
-  $success = locale_language_delete($langcode);
-
-  if ($success) {
-    $variables = array('%locale' => $language->name);
-    drupal_set_message(t('The language %locale has been removed.', $variables));
-  }
-
-  $form_state['redirect'] = 'admin/config/regional/language';
-}
-
-/**
  * Setting for language negotiation options
  */
 function locale_languages_configure_form() {
diff --git a/core/modules/locale/locale.bulk.inc b/core/modules/locale/locale.bulk.inc
index 4051674..4ba2661 100644
--- a/core/modules/locale/locale.bulk.inc
+++ b/core/modules/locale/locale.bulk.inc
@@ -18,14 +18,15 @@ function locale_translate_import_form($form) {
     unset($names['en']);
   }
 
+  include_once drupal_get_path('module', 'language') . '/language.admin.inc';
   if (!count($names)) {
-    $languages = _locale_prepare_predefined_list();
+    $languages = language_admin_predefined_list();
     $default = key($languages);
   }
   else {
     $languages = array(
       t('Already added languages') => $names,
-      t('Languages not yet added') => _locale_prepare_predefined_list()
+      t('Languages not yet added') => language_admin_predefined_list()
     );
     $default = key($names);
   }
@@ -75,7 +76,7 @@ function locale_translate_import_form_submit($form, &$form_state) {
       $language = (object) array(
         'language' => $langcode,
       );
-      locale_language_save($language);
+      language_save($language);
       drupal_set_message(t('The language %language has been created.', array('%language' => t($predefined[$langcode][0]))));
     }
 
diff --git a/core/modules/locale/locale.info b/core/modules/locale/locale.info
index 748d274..28bbd03 100644
--- a/core/modules/locale/locale.info
+++ b/core/modules/locale/locale.info
@@ -1,7 +1,7 @@
 name = Locale
-description = Adds language handling functionality and enables the translation of the user interface to languages other than English.
+description = Provides language negotiation functionality and user interface translation to languages other than English.
 package = Core
 version = VERSION
 core = 8.x
+dependencies[] = language
 files[] = locale.test
-configure = admin/config/regional/language
diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install
index 4ae03fc..d2034b5 100644
--- a/core/modules/locale/locale.install
+++ b/core/modules/locale/locale.install
@@ -6,15 +6,6 @@
  */
 
 /**
- * Implements hook_install().
- */
-function locale_install() {
-  // Add the default language to the database too.
-  include_once DRUPAL_ROOT . '/core/includes/locale.inc';
-  locale_language_save(language_default());
-}
-
-/**
  * Implements hook_uninstall().
  */
 function locale_uninstall() {
@@ -35,8 +26,6 @@ function locale_uninstall() {
   }
 
   // Clear variables.
-  variable_del('language_default');
-  variable_del('language_count');
   variable_del('language_types');
   variable_del('locale_language_negotiation_url_part');
   variable_del('locale_language_negotiation_url_prefixes');
@@ -60,60 +49,12 @@ function locale_uninstall() {
   foreach (node_type_get_types() as $type => $content_type) {
     $setting = variable_del("language_content_type_$type");
   }
-
-  // Switch back to English: with a $language->language value different from 'en'
-  // successive calls of t() might result in calling locale(), which in turn might
-  // try to query the unexisting {locales_source} and {locales_target} tables.
-  drupal_language_initialize();
-
 }
 
 /**
  * Implements hook_schema().
  */
 function locale_schema() {
-  $schema['languages'] = array(
-    'description' => 'List of all available languages in the system.',
-    'fields' => array(
-      'language' => array(
-        'type' => 'varchar',
-        'length' => 12,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => "Language code, e.g. 'de' or 'en-US'.",
-      ),
-      'name' => array(
-        'type' => 'varchar',
-        'length' => 64,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => 'Language name.',
-      ),
-      'direction' => array(
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'description' => 'Direction of language (Left-to-Right = 0, Right-to-Left = 1).',
-      ),
-      'enabled' => array(
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'description' => 'Enabled flag (1 = Enabled, 0 = Disabled).',
-      ),
-      'weight' => array(
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-        'description' => 'Weight, used in lists of languages.',
-      ),
-    ),
-    'primary key' => array('language'),
-    'indexes' => array(
-      'list' => array('weight', 'name'),
-    ),
-  );
-
   $schema['locales_source'] = array(
     'description' => 'List of English source strings.',
     'fields' => array(
@@ -175,7 +116,7 @@ function locale_schema() {
         'length' => 12,
         'not null' => TRUE,
         'default' => '',
-        'description' => 'Language code. References {languages}.language.',
+        'description' => 'Language code. References {language}.language.',
       ),
       'plid' => array(
         'type' => 'int',
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 5168a24..8e0da90 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -38,11 +38,7 @@ function locale_help($path, $arg) {
       return $output;
 
     case 'admin/config/regional/language':
-      $output = '<p>' . t('With multiple languages enabled, interface text can be translated, registered users may select their preferred language, and authors can assign a specific language to content. <a href="@translations">Download contributed translations</a> from Drupal.org.', array('@translations' => 'http://localize.drupal.org')) . '</p>';
-      return $output;
-
-    case 'admin/config/regional/language/add':
-      return '<p>' . t('Add a language to be supported by your site. If your desired language is not available, pick <em>Custom language...</em> at the end and provide a language code and other details manually.') . '</p>';
+      return '<p>' . t('Interface text can be translated. <a href="@translations">Download contributed translations</a> from Drupal.org.', array('@translations' => 'http://localize.drupal.org')) . '</p>';
 
     case 'admin/config/regional/language/configure':
       $output = '<p>' . t("Define how to decide which language is used to display page elements (primarily text provided by Drupal and modules, such as field labels and help text). This decision is made by evaluating a series of detection methods for languages; the first detection method that gets a result will determine which language is used for that type of text. Define the order of evaluation of language detection methods on this page.") . '</p>';
@@ -76,30 +72,7 @@ function locale_help($path, $arg) {
  * Implements hook_menu().
  */
 function locale_menu() {
-  // Manage languages
-  $items['admin/config/regional/language'] = array(
-    'title' => 'Languages',
-    'description' => 'Configure languages for content and the user interface.',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('locale_language_overview_form'),
-    'access arguments' => array('administer languages'),
-    'file' => 'locale.admin.inc',
-    'weight' => -10,
-  );
-  $items['admin/config/regional/language/overview'] = array(
-    'title' => 'List',
-    'weight' => 0,
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-  $items['admin/config/regional/language/add'] = array(
-    'title' => 'Add language',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('locale_languages_add_form'),
-    'access arguments' => array('administer languages'),
-    'weight' => 5,
-    'type' => MENU_LOCAL_ACTION,
-    'file' => 'locale.admin.inc',
-  );
+  // Language negotiation.
   $items['admin/config/regional/language/configure'] = array(
     'title' => 'Detection and selection',
     'page callback' => 'drupal_get_form',
@@ -125,22 +98,8 @@ function locale_menu() {
     'file' => 'locale.admin.inc',
     'type' => MENU_VISIBLE_IN_BREADCRUMB,
   );
-  $items['admin/config/regional/language/edit/%language'] = array(
-    'title' => 'Edit language',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('locale_languages_edit_form', 5),
-    'access arguments' => array('administer languages'),
-    'file' => 'locale.admin.inc',
-  );
-  $items['admin/config/regional/language/delete/%language'] = array(
-    'title' => 'Confirm',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('locale_languages_delete_form', 5),
-    'access arguments' => array('administer languages'),
-    'file' => 'locale.admin.inc',
-  );
 
-  // Translation functionality
+  // Translation functionality.
   $items['admin/config/regional/translate'] = array(
     'title' => 'User interface translation',
     'description' => 'Translate the built-in user interface.',
@@ -246,9 +205,6 @@ function locale_init() {
  */
 function locale_permission() {
   return array(
-    'administer languages' => array(
-      'title' => t('Administer languages'),
-    ),
     'translate interface' => array(
       'title' => t('Translate interface texts'),
     ),
@@ -256,20 +212,6 @@ function locale_permission() {
 }
 
 /**
- * Loads a language object from the database.
- *
- * @param $langcode
- *   The language code.
- *
- * @return
- *   A fully-populated language object or FALSE.
- */
-function language_load($langcode) {
-  $languages = language_list();
-  return isset($languages[$langcode]) ? $languages[$langcode] : FALSE;
-}
-
-/**
  * Form builder callback to display language selection widget.
  *
  * @ingroup forms
@@ -408,14 +350,6 @@ function locale_field_node_form_submit($form, &$form_state) {
  */
 function locale_theme() {
   return array(
-    'locale_language_overview_form_table' => array(
-      'render element' => 'form',
-      'file' => 'locale.admin.inc',
-    ),
-    'locale_language_operations' => array(
-      'render element' => 'elements',
-      'file' => 'locale.admin.inc',
-    ),
     'locale_languages_configure_form' => array(
       'render element' => 'form',
     ),
@@ -608,9 +542,9 @@ function locale_modules_disabled($modules) {
 }
 
 /**
- * Implements hook_locale_language_insert().
+ * Implements hook_language_insert().
  */
-function locale_locale_language_insert($language) {
+function locale_language_insert($language) {
   // Add new language to the list of language prefixes.
   $prefixes = locale_language_negotiation_url_prefixes();
   $prefixes[$language->language] = (empty($language->default) ? $language->language : '');
@@ -620,12 +554,18 @@ function locale_locale_language_insert($language) {
   $domains = locale_language_negotiation_url_domains();
   $domains[$language->language] = '';
   locale_language_negotiation_url_domains_save($domains);
+
+  // @todo move these two cache clears out. See http://drupal.org/node/1293252
+  // Changing the language settings impacts the interface.
+  cache_clear_all('*', 'cache_page', TRUE);
+  // Force JavaScript translation file re-creation for the new language.
+  _locale_invalidate_js($language->language);
 }
 
 /**
- * Implements hook_locale_language_update().
+ * Implements hook_language_update().
  */
-function locale_locale_language_update($language) {
+function locale_language_update($language) {
 
   // If the language is the default, then ensure that no other languages have
   // blank prefix codes.
@@ -639,12 +579,17 @@ function locale_locale_language_update($language) {
     locale_language_negotiation_url_prefixes_save($prefixes);
   }
 
+  // @todo move these two cache clears out. See http://drupal.org/node/1293252
+  // Changing the language settings impacts the interface.
+  cache_clear_all('*', 'cache_page', TRUE);
+  // Force JavaScript translation file re-creation for the modified language.
+  _locale_invalidate_js($language->language);
 }
 
 /**
- * Implements hook_locale_language_delete().
+ * Implements hook_language_delete().
  */
-function locale_locale_language_delete($language) {
+function locale_language_delete($language) {
   // Remove language from language prefix list.
   $prefixes = locale_language_negotiation_url_prefixes();
   unset($prefixes[$language->language]);
@@ -654,6 +599,19 @@ function locale_locale_language_delete($language) {
   $domains = locale_language_negotiation_url_domains();
   unset($domains[$language->language]);
   locale_language_negotiation_url_domains_save($domains);
+
+  // Remove translations.
+  db_delete('locales_target')
+    ->condition('language', $language->language)
+    ->execute();
+
+  _locale_invalidate_js($language->language);
+
+  // Changing the language settings impacts the interface:
+  cache('page')->flush();
+
+  // Clearing all locale cache from database
+  cache()->delete('locale:' . $language->language);
 }
 
 
@@ -833,51 +791,6 @@ function locale_language_list($field = 'name', $all = FALSE) {
 }
 
 /**
- * Delete a language.
- *
- * @param $langcode
- *   Language code of the language to be deleted.
- * @return
- *   TRUE if language is successfully deleted. Otherwise FALSE.
- */
-function locale_language_delete($langcode) {
-  $languages = language_list();
-  if (isset($languages[$langcode])) {
-    $language = $languages[$langcode];
-
-    module_invoke_all('locale_language_delete', $language);
-
-    // Remove translations first.
-    db_delete('locales_target')
-      ->condition('language', $language->language)
-      ->execute();
-
-    // Remove the language.
-    db_delete('languages')
-      ->condition('language', $language->language)
-      ->execute();
-
-    if ($language->enabled) {
-      variable_set('language_count', variable_get('language_count', 1) - 1);
-    }
-
-    drupal_static_reset('language_list');
-    _locale_invalidate_js($language->language);
-
-    // Changing the language settings impacts the interface:
-    cache('page')->flush();
-
-    // Clearing all locale cache from database
-    cache()->delete('locale:' . $language->language);
-
-    $variables = array('%locale' => $language->name);
-    watchdog('locale', 'The language %locale has been removed.', $variables);
-    return TRUE;
-  }
-  return FALSE;
-}
-
-/**
  * Implements hook_modules_installed().
  */
 function locale_modules_installed($modules) {
@@ -1133,9 +1046,9 @@ function locale_form_comment_form_alter(&$form, &$form_state, $form_id) {
 }
 
 /**
- * Implements hook_form_FORM_ID_alter() for locale_language_overview_form().
+ * Implements hook_form_FORM_ID_alter() for language_admin_overview_form().
  */
-function locale_form_locale_language_overview_form_alter(&$form, &$form_state) {
+function locale_form_language_admin_overview_form_alter(&$form, &$form_state) {
   $languages = $form['languages']['#languages'];
 
   $total_strings = db_query("SELECT COUNT(*) FROM {locales_source}")->fetchField();
@@ -1179,23 +1092,50 @@ function locale_form_locale_language_overview_form_alter(&$form, &$form_state) {
 }
 
 /**
- * Implements hook_form_FORM_ID_alter() for locale_languages_edit_form().
+ * Implements hook_form_FORM_ID_alter() for language_admin_add_form(().
+ */
+function locale_form_language_admin_add_form_alter(&$form, &$form_state) {
+  $form['predefined_submit']['#submit'][] = 'locale_form_language_admin_add_form_alter_submit';
+  $form['custom_language']['submit']['#submit'][] = 'locale_form_language_admin_add_form_alter_submit';
+}
+
+/**
+ * Set a batch for newly added language.
+ */
+function locale_form_language_admin_add_form_alter_submit($form, $form_state) {
+  if (empty($form_state['values']['predefined_langcode']) || $form_state['values']['predefined_langcode'] == 'custom') {
+    $langcode = $form_state['values']['langcode'];
+  }
+  else {
+    $langcode = $form_state['values']['predefined_langcode'];
+  }
+
+  // See if we have language files to import for the newly added
+  // language, collect and import them.
+  include_once drupal_get_path('module', 'locale') . '/locale.bulk.inc';
+  if ($batch = locale_translate_batch_import_files($langcode, TRUE)) {
+    batch_set($batch);
+  }
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() for language_admin_edit_form().
  */
-function locale_form_locale_languages_edit_form_alter(&$form, &$form_state) {
+function locale_form_language_admin_edit_form_alter(&$form, &$form_state) {
   if ($form['langcode']['#type'] == 'value' && $form['langcode']['#value'] == 'en') {
     $form['locale_translate_english'] = array(
       '#title' => t('Enable interface translation to English'),
       '#type' => 'checkbox',
       '#default_value' => locale_translate_english(),
     );
-    $form['#submit'][] = 'locale_form_locale_languages_edit_form_alter_submit';
+    $form['#submit'][] = 'locale_form_language_admin_edit_form_alter_submit';
   }
 }
 
 /**
  * Submission handler to record our custom setting.
  */
-function locale_form_locale_languages_edit_form_alter_submit($form, $form_state) {
+function locale_form_language_admin_edit_form_alter_submit($form, $form_state) {
   variable_set('locale_translate_english', $form_state['values']['locale_translate_english']);
 }
 
diff --git a/core/modules/locale/locale.test b/core/modules/locale/locale.test
index fb5bb37..231ae4e 100644
--- a/core/modules/locale/locale.test
+++ b/core/modules/locale/locale.test
@@ -132,8 +132,9 @@ class LocaleConfigurationTest extends DrupalWebTestCase {
     // Delete the language for real. This a confirm form, we do not need any
     // fields changed.
     $this->drupalPost('admin/config/regional/language/delete/' . $langcode, array(), t('Delete'));
-    // We need raw here because %locale will add HTML.
-    $this->assertRaw(t('The language %locale has been removed.', array('%locale' => $name)), t('The test language has been removed.'));
+    // We need raw here because %language and %langcode will add HTML.
+    $t_args = array('%language' => $name, '%langcode' => $langcode);
+    $this->assertRaw(t('The %language (%langcode) language has been removed.', $t_args)), t('The test language has been removed.'));
     $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
     // Verify that language is no longer found.
     $this->drupalGet('admin/config/regional/language/delete/' . $langcode);
@@ -154,8 +155,9 @@ class LocaleConfigurationTest extends DrupalWebTestCase {
     $enabled = language_list('enabled');
     // Delete the disabled language.
     $this->drupalPost('admin/config/regional/language/delete/fr', array(), t('Delete'));
-    // We need raw here because %locale will add HTML.
-    $this->assertRaw(t('The language %locale has been removed.', array('%locale' => 'French')), t('Disabled language has been removed.'));
+    // We need raw here because %language and %langcode will add HTML.
+    $t_args = array('%language' => 'French', '%langcode' => 'fr');
+    $this->assertRaw(t('The %language (%langcode) language has been removed.', $t_args)), t('Disabled language has been removed.'));
     $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
     // Verify that language is no longer found.
     $this->drupalGet('admin/config/regional/language/delete/fr');
@@ -191,8 +193,9 @@ class LocaleConfigurationTest extends DrupalWebTestCase {
     $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
 
     $this->drupalPost('admin/config/regional/language/delete/en', array(), t('Delete'));
-    // We need raw here because %locale will add HTML.
-    $this->assertRaw(t('The language %locale has been removed.', array('%locale' => 'English')), t('The English language has been removed.'));
+    // We need raw here because %language and %langcode will add HTML.
+    $t_args = array('%language' => 'English', '%langcode' => 'en');
+    $this->assertRaw(t('The %language (%langcode) language has been removed.', $t_args)), t('The English language has been removed.'));
   }
 
 }
@@ -411,8 +414,9 @@ class LocaleTranslationFunctionalTest extends DrupalWebTestCase {
     $path = 'admin/config/regional/language/delete/' . $langcode;
     // This a confirm form, we do not need any fields changed.
     $this->drupalPost($path, array(), t('Delete'));
-    // We need raw here because %locale will add HTML.
-    $this->assertRaw(t('The language %locale has been removed.', array('%locale' => $name)), t('The test language has been removed.'));
+    // We need raw here because %language and %langcode will add HTML.
+    $t_args = array('%language' => $name, '%langcode' => $langcode);
+    $this->assertRaw(t('The %language (%langcode) language has been removed.', $t_args)), t('The test language has been removed.'));
     // Reload to remove $name.
     $this->drupalGet($path);
     // Verify that language is no longer found.
@@ -1196,7 +1200,7 @@ class LocaleUninstallFunctionalTest extends DrupalWebTestCase {
    * Check if the values of the Locale variables are correct after uninstall.
    */
   function testUninstallProcess() {
-    $locale_module = array('locale');
+    $locale_module = array('locale', 'language');
 
     // Add a new language and optionally set it as default.
     require_once DRUPAL_ROOT . '/core/includes/locale.inc';
@@ -1206,7 +1210,7 @@ class LocaleUninstallFunctionalTest extends DrupalWebTestCase {
       'name' => 'French',
       'default' => $this->language == 'fr',
     );
-    locale_language_save($language);
+    language_save($language);
 
     // Check the UI language.
     drupal_language_initialize();
@@ -2103,11 +2107,11 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
     $language = (object) array(
       'language' => $langcode_browser_fallback,
     );
-    locale_language_save($language);
+    language_save($language);
     $language = (object) array(
       'language' => $langcode,
     );
-    locale_language_save($language);
+    language_save($language);
 
     // We will look for this string in the admin/config screen to see if the
     // corresponding translated string is shown.
@@ -2252,7 +2256,7 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase {
     $language = (object) array(
       'language' => $langcode_browser_fallback,
     );
-    locale_language_save($language);
+    language_save($language);
     $languages = language_list();
 
     // Enable the path prefix for the default language: this way any unprefixed
@@ -2401,7 +2405,7 @@ class LocaleMultilingualFieldsFunctionalTest extends DrupalWebTestCase {
       'language' => 'it',
       'name' => 'Italian',
     );
-    locale_language_save($language);
+    language_save($language);
 
     // Enable URL language detection and selection.
     $edit = array('language[enabled][locale-url]' => '1');
diff --git a/core/modules/node/node.install b/core/modules/node/node.install
index a6d0b7a..654624c 100644
--- a/core/modules/node/node.install
+++ b/core/modules/node/node.install
@@ -33,7 +33,7 @@ function node_schema() {
         'default' => '',
       ),
       'language' => array(
-        'description' => 'The {languages}.language of this node.',
+        'description' => 'The {language}.language of this node.',
         'type' => 'varchar',
         'length' => 12,
         'not null' => TRUE,
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 6def162..1699a06 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -4122,9 +4122,9 @@ function node_file_download_access($field, $entity_type, $entity) {
 }
 
 /**
- * Implements hook_locale_language_delete().
+ * Implements hook_language_delete().
  */
-function node_locale_language_delete($language) {
+function node_language_delete($language) {
   // On nodes with this language, unset the language
   db_update('node')
     ->fields(array('language' => ''))
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 6711471..09a8432 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -770,7 +770,7 @@ function system_schema() {
         'not null' => TRUE,
       ),
       'language' => array(
-        'description' => 'A {languages}.language for this format to be used with.',
+        'description' => 'A {language}.language for this format to be used with.',
         'type' => 'varchar',
         'length' => 12,
         'not null' => TRUE,
diff --git a/core/modules/system/system.test b/core/modules/system/system.test
index 4e3761d..12797ed 100644
--- a/core/modules/system/system.test
+++ b/core/modules/system/system.test
@@ -379,10 +379,10 @@ class ModuleDependencyTestCase extends ModuleTestCase {
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
     $this->assertText(t('Some required modules must be enabled'), t('Dependency required.'));
 
-    $this->assertModules(array('translation', 'locale'), FALSE);
+    $this->assertModules(array('translation', 'locale', 'language'), FALSE);
 
     // Assert that the locale tables weren't enabled.
-    $this->assertTableCount('languages', FALSE);
+    $this->assertTableCount('language', FALSE);
     $this->assertTableCount('locale', FALSE);
 
     $this->drupalPost(NULL, NULL, t('Continue'));
@@ -391,7 +391,7 @@ class ModuleDependencyTestCase extends ModuleTestCase {
     $this->assertModules(array('translation', 'locale'), TRUE);
 
     // Assert that the locale tables were enabled.
-    $this->assertTableCount('languages', TRUE);
+    $this->assertTableCount('language', TRUE);
     $this->assertTableCount('locale', TRUE);
   }
 
@@ -1248,7 +1248,7 @@ class DateTimeFunctionalTest extends DrupalWebTestCase {
       'language' => 'de',
       'default' => TRUE,
     );
-    locale_language_save($language);
+    language_save($language);
 
     $date_format = array(
       'type' => 'short',
diff --git a/core/modules/translation/translation.test b/core/modules/translation/translation.test
index 0e801c1..776825a 100644
--- a/core/modules/translation/translation.test
+++ b/core/modules/translation/translation.test
@@ -17,7 +17,7 @@ class TranslationTestCase extends DrupalWebTestCase {
   }
 
   function setUp() {
-    parent::setUp('locale', 'translation', 'translation_test');
+    parent::setUp('language', 'locale', 'translation', 'translation_test');
 
     // Setup users.
     $this->admin_user = $this->drupalCreateUser(array('bypass node access', 'administer nodes', 'administer languages', 'administer content types', 'administer blocks', 'access administration pages', 'translate content'));
@@ -291,7 +291,7 @@ class TranslationTestCase extends DrupalWebTestCase {
       $this->assertTrue(array_key_exists($language_code, $languages), t('Language was installed successfully.'));
 
       if (array_key_exists($language_code, $languages)) {
-        $this->assertRaw(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array('%language' => $languages[$language_code]->name, '@locale-help' => url('admin/help/locale'))), t('Language has been created.'));
+        $this->assertRaw(t('The language %language has been created and can now be used.', array('%language' => $languages[$language_code]->name)), t('Language has been created.'));
       }
     }
     elseif ($this->xpath('//input[@type="checkbox" and @name=:name and @checked="checked"]', array(':name' => 'languages[' . $language_code . '][enabled]'))) {
