From 43f943893e74c4aef16f5d18028a285ac76545eb Mon Sep 17 00:00:00 2001
From: Bram Goffings <bramgoffings@gmail.com>
Date: Mon, 21 May 2012 13:52:20 +0200
Subject: [PATCH] locale tests to PSR-0

---
 .../locale/Tests/LocaleCommentLanguageTest.php     |  108 +
 .../lib/Drupal/locale/Tests/LocaleContentTest.php  |  210 ++
 .../Drupal/locale/Tests/LocaleDateFormatsTest.php  |   82 +
 .../lib/Drupal/locale/Tests/LocaleExportTest.php   |  152 ++
 .../locale/Tests/LocaleImportFunctionalTest.php    |  487 +++++
 .../lib/Drupal/locale/Tests/LocaleInstallTest.php  |   40 +
 .../locale/Tests/LocaleJavascriptTranslation.php   |  100 +
 .../locale/Tests/LocaleMultilingualFieldsTest.php  |  137 ++
 .../lib/Drupal/locale/Tests/LocalePathTest.php     |  149 ++
 .../Drupal/locale/Tests/LocalePluralFormatTest.php |  323 +++
 .../Drupal/locale/Tests/LocaleTranslationTest.php  |  418 ++++
 .../locale/Tests/LocaleUninstallFrenchTest.php     |   31 +
 .../Drupal/locale/Tests/LocaleUninstallTest.php    |  132 ++
 core/modules/locale/locale.info                    |    1 -
 core/modules/locale/locale.test                    | 2263 --------------------
 15 files changed, 2369 insertions(+), 2264 deletions(-)
 create mode 100644 core/modules/locale/lib/Drupal/locale/Tests/LocaleCommentLanguageTest.php
 create mode 100644 core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php
 create mode 100644 core/modules/locale/lib/Drupal/locale/Tests/LocaleDateFormatsTest.php
 create mode 100644 core/modules/locale/lib/Drupal/locale/Tests/LocaleExportTest.php
 create mode 100644 core/modules/locale/lib/Drupal/locale/Tests/LocaleImportFunctionalTest.php
 create mode 100644 core/modules/locale/lib/Drupal/locale/Tests/LocaleInstallTest.php
 create mode 100644 core/modules/locale/lib/Drupal/locale/Tests/LocaleJavascriptTranslation.php
 create mode 100644 core/modules/locale/lib/Drupal/locale/Tests/LocaleMultilingualFieldsTest.php
 create mode 100644 core/modules/locale/lib/Drupal/locale/Tests/LocalePathTest.php
 create mode 100644 core/modules/locale/lib/Drupal/locale/Tests/LocalePluralFormatTest.php
 create mode 100644 core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php
 create mode 100644 core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallFrenchTest.php
 create mode 100644 core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
 delete mode 100644 core/modules/locale/locale.test

diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleCommentLanguageTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCommentLanguageTest.php
new file mode 100644
index 0000000..16fc83f
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleCommentLanguageTest.php
@@ -0,0 +1,108 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\locale\Tests\LocaleCommentLanguageTest.
+ */
+
+namespace Drupal\locale\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Functional tests for comment language.
+ */
+class LocaleCommentLanguageTest extends WebTestBase {
+  protected $profile = 'standard';
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Comment language',
+      'description' => 'Tests for comment language.',
+      'group' => 'Locale',
+    );
+  }
+
+  function setUp() {
+    // We also use language_test module here to be able to turn on content
+    // language negotiation. Drupal core does not provide a way in itself
+    // to do that.
+    parent::setUp('locale', 'language_test');
+
+    // Create and login user.
+    $admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer languages', 'access administration pages', 'administer content types', 'create article content'));
+    $this->drupalLogin($admin_user);
+
+    // Add language.
+    $edit = array('predefined_langcode' => 'fr');
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+
+    // Set "Article" content type to use multilingual support.
+    $edit = array('node_type_language' => 1);
+    $this->drupalPost('admin/structure/types/manage/article', $edit, t('Save content type'));
+
+    // Enable content language negotiation UI.
+    variable_set('language_test_content_language_type', TRUE);
+
+    // Set interface language detection to user and content language detection
+    // to URL. Disable inheritance from interface language to ensure content
+    // language will fall back to the default language if no URL language can be
+    // detected.
+    $edit = array(
+      'language_interface[enabled][language-user]' => TRUE,
+      'language_content[enabled][language-url]' => TRUE,
+      'language_content[enabled][language-interface]' => FALSE,
+    );
+    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
+
+    // Change user language preference, this way interface language is always
+    // French no matter what path prefix the URLs have.
+    $edit = array('preferred_langcode' => 'fr');
+    $this->drupalPost("user/{$admin_user->uid}/edit", $edit, t('Save'));
+  }
+
+  /**
+   * Test that comment language is properly set.
+   */
+  function testCommentLanguage() {
+    drupal_static_reset('language_list');
+
+    // Create two nodes, one for english and one for french, and comment each
+    // node using both english and french as content language by changing URL
+    // language prefixes. Meanwhile interface language is always French, which
+    // is the user language preference. This way we can ensure that node
+    // language and interface language do not influence comment language, as
+    // only content language has to.
+    foreach (language_list() as $node_langcode => $node_language) {
+      $langcode_not_specified = LANGUAGE_NOT_SPECIFIED;
+
+      // Create "Article" content.
+      $title = $this->randomName();
+      $edit = array(
+        "title" => $title,
+        "body[$langcode_not_specified][0][value]" => $this->randomName(),
+        "langcode" => $node_langcode,
+      );
+      $this->drupalPost("node/add/article", $edit, t('Save'));
+      $node = $this->drupalGetNodeByTitle($title);
+
+      $prefixes = language_negotiation_url_prefixes();
+      foreach (language_list() as $langcode => $language) {
+        // Post a comment with content language $langcode.
+        $prefix = empty($prefixes[$langcode]) ? '' : $prefixes[$langcode] . '/';
+        $edit = array("comment_body[$langcode_not_specified][0][value]" => $this->randomName());
+        $this->drupalPost("{$prefix}node/{$node->nid}", $edit, t('Save'));
+
+        // Check that comment language matches the current content language.
+        $comment = db_select('comment', 'c')
+          ->fields('c')
+          ->condition('nid', $node->nid)
+          ->orderBy('cid', 'DESC')
+          ->execute()
+          ->fetchObject();
+        $args = array('%node_language' => $node_langcode, '%comment_language' => $comment->langcode, '%langcode' => $langcode);
+        $this->assertEqual($comment->langcode, $langcode, t('The comment posted with content language %langcode and belonging to the node with language %node_language has language %comment_language', $args));
+      }
+    }
+  }
+}
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php
new file mode 100644
index 0000000..0c5cea3
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleContentTest.php
@@ -0,0 +1,210 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\locale\Tests\LocaleContentTest.
+ */
+
+namespace Drupal\locale\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Functional tests for multilingual support on nodes.
+ */
+class LocaleContentTest extends WebTestBase {
+  protected $profile = 'standard';
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Content language settings',
+      'description' => 'Checks you can enable multilingual support on content types and configure a language for a node.',
+      'group' => 'Locale',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('locale');
+  }
+
+  /**
+   * Verifies that machine name fields are always LTR.
+   */
+  function testMachineNameLTR() {
+    // User to add and remove language.
+    $admin_user = $this->drupalCreateUser(array('administer languages', 'administer content types', 'access administration pages'));
+
+    // Log in as admin.
+    $this->drupalLogin($admin_user);
+
+    // Verify that the machine name field is LTR for a new content type.
+    $this->drupalGet('admin/structure/types/add');
+    $this->assertFieldByXpath('//input[@name="type" and @dir="ltr"]', NULL, 'The machine name field is LTR when no additional language is configured.');
+
+    // Install the Arabic language (which is RTL) and configure as the default.
+    $edit = array();
+    $edit['predefined_langcode'] = 'ar';
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+
+    $edit = array();
+    $edit['site_default'] = 'ar';
+    $this->drupalPost(NULL, $edit, t('Save configuration'));
+
+    // Verify that the machine name field is still LTR for a new content type.
+    $this->drupalGet('admin/structure/types/add');
+    $this->assertFieldByXpath('//input[@name="type" and @dir="ltr"]', NULL, 'The machine name field is LTR when the default language is RTL.');
+  }
+
+  /**
+   * Test if a content type can be set to multilingual and language is present.
+   */
+  function testContentTypeLanguageConfiguration() {
+    global $base_url;
+
+    // User to add and remove language.
+    $admin_user = $this->drupalCreateUser(array('administer languages', 'administer content types', 'access administration pages'));
+    // User to create a node.
+    $web_user = $this->drupalCreateUser(array('create article content', 'create page content', 'edit any page content'));
+
+    // Add custom language.
+    $this->drupalLogin($admin_user);
+    // Code for the language.
+    $langcode = 'xx';
+    // The English name for the language.
+    $name = $this->randomName(16);
+    $edit = array(
+      'predefined_langcode' => 'custom',
+      'langcode' => $langcode,
+      'name' => $name,
+      'direction' => '0',
+    );
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
+
+    // Set "Basic page" content type to use multilingual support.
+    $this->drupalGet('admin/structure/types/manage/page');
+    $this->assertText(t('Multilingual support'), t('Multilingual support fieldset present on content type configuration form.'));
+    $edit = array(
+      'node_type_language' => 1,
+    );
+    $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
+    $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.'));
+    $this->drupalLogout();
+
+    // Verify language selection is not present on add article form.
+    $this->drupalLogin($web_user);
+    $this->drupalGet('node/add/article');
+    // Verify language select list is not present.
+    $this->assertNoFieldByName('language', NULL, t('Language select not present on add article form.'));
+
+    // Verify language selection appears on add "Basic page" form.
+    $this->drupalGet('node/add/page');
+    // Verify language select list is present.
+    $this->assertFieldByName('langcode', NULL, t('Language select present on add Basic page form.'));
+    // Ensure language appears.
+    $this->assertText($name, t('Language present.'));
+
+    // Create "Basic page" content.
+    $node_title = $this->randomName();
+    $node_body =  $this->randomName();
+    $edit = array(
+      'type' => 'page',
+      'title' => $node_title,
+      'body' => array($langcode => array(array('value' => $node_body))),
+      'langcode' => $langcode,
+    );
+    $node = $this->drupalCreateNode($edit);
+    // Edit the content and ensure correct language is selected.
+    $path = 'node/' . $node->nid . '/edit';
+    $this->drupalGet($path);
+    $this->assertRaw('<option value="' . $langcode . '" selected="selected">' .  $name . '</option>', t('Correct language selected.'));
+    // Ensure we can change the node language.
+    $edit = array(
+      'langcode' => 'en',
+    );
+    $this->drupalPost($path, $edit, t('Save'));
+    $this->assertRaw(t('%title has been updated.', array('%title' => $node_title)), t('Basic page content updated.'));
+
+    $this->drupalLogout();
+  }
+
+  /**
+   * Test if a dir and lang tags exist in node's attributes.
+   */
+  function testContentTypeDirLang() {
+    // User to add and remove language.
+    $admin_user = $this->drupalCreateUser(array('administer languages', 'administer content types', 'access administration pages'));
+    // User to create a node.
+    $web_user = $this->drupalCreateUser(array('create article content', 'edit own article content'));
+
+    // Login as admin.
+    $this->drupalLogin($admin_user);
+
+    // Install Arabic language.
+    $edit = array();
+    $edit['predefined_langcode'] = 'ar';
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+
+    // Install Spanish language.
+    $edit = array();
+    $edit['predefined_langcode'] = 'es';
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+
+    // Set "Article" content type to use multilingual support.
+    $this->drupalGet('admin/structure/types/manage/article');
+    $edit = array(
+      'node_type_language' => 1,
+    );
+    $this->drupalPost('admin/structure/types/manage/article', $edit, t('Save content type'));
+    $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Article')), t('Article content type has been updated.'));
+    $this->drupalLogout();
+
+    // Login as web user to add new article.
+    $this->drupalLogin($web_user);
+
+    // Create three nodes: English, Arabic and Spanish.
+    $node_en = $this->createNodeArticle('en');
+    $node_ar = $this->createNodeArticle('ar');
+    $node_es = $this->createNodeArticle('es');
+
+    $this->drupalGet('node');
+
+    // Check if English node does not have lang tag.
+    $pattern = '|id="node-' . $node_en->nid . '"[^<>]*lang="en"|';
+    $this->assertNoPattern($pattern, t('The lang tag has not been assigned to the English node.'));
+
+    // Check if English node does not have dir tag.
+    $pattern = '|id="node-' . $node_en->nid . '"[^<>]*dir="ltr"|';
+    $this->assertNoPattern($pattern, t('The dir tag has not been assigned to the English node.'));
+
+    // Check if Arabic node has lang="ar" & dir="rtl" tags.
+    $pattern = '|id="node-' . $node_ar->nid . '"[^<>]*lang="ar" dir="rtl"|';
+    $this->assertPattern($pattern, t('The lang and dir tags have been assigned correctly to the Arabic node.'));
+
+    // Check if Spanish node has lang="es" tag.
+    $pattern = '|id="node-' . $node_es->nid . '"[^<>]*lang="es"|';
+    $this->assertPattern($pattern, t('The lang tag has been assigned correctly to the Spanish node.'));
+
+    // Check if Spanish node does not have dir="ltr" tag.
+    $pattern = '|id="node-' . $node_es->nid . '"[^<>]*lang="es" dir="ltr"|';
+    $this->assertNoPattern($pattern, t('The dir tag has not been assigned to the Spanish node.'));
+
+    $this->drupalLogout();
+  }
+
+  /**
+   * Create node in a specific language.
+   */
+  protected function createNodeArticle($langcode) {
+    $this->drupalGet('node/add/article');
+    $node_title = $this->randomName();
+    $node_body =  $this->randomName();
+    $edit = array(
+      'type' => 'article',
+      'title' => $node_title,
+      'body' => array($langcode => array(array('value' => $node_body))),
+      'langcode' => $langcode,
+      'promote' => 1,
+    );
+    return $this->drupalCreateNode($edit);
+  }
+}
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleDateFormatsTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleDateFormatsTest.php
new file mode 100644
index 0000000..e5514b8
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleDateFormatsTest.php
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\locale\Tests\LocaleDateFormatsTest.
+ */
+
+namespace Drupal\locale\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Functional tests for localizing date formats.
+ */
+class LocaleDateFormatsTest extends WebTestBase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Localize date formats',
+      'description' => 'Tests for the localization of date formats.',
+      'group' => 'Locale',
+    );
+  }
+
+  function setUp() {
+    parent::setUp(array('node', 'locale'));
+
+    // Create Article node type.
+    $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
+
+    // Create and login user.
+    $admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer languages', 'access administration pages', 'create article content'));
+    $this->drupalLogin($admin_user);
+  }
+
+  /**
+   * Functional tests for localizing date formats.
+   */
+  function testLocalizeDateFormats() {
+    // Add language.
+    $edit = array(
+      'predefined_langcode' => 'fr',
+    );
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+
+    // Set language negotiation.
+    $language_type = LANGUAGE_TYPE_INTERFACE;
+    $edit = array(
+      "{$language_type}[enabled][language-url]" => TRUE,
+    );
+    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
+
+    // Configure date formats.
+    $this->drupalGet('admin/config/regional/date-time/locale');
+    $this->assertText('French', 'Configured languages appear.');
+    $edit = array(
+      'date_format_long' => 'd.m.Y - H:i',
+      'date_format_medium' => 'd.m.Y - H:i',
+      'date_format_short' => 'd.m.Y - H:i',
+    );
+    $this->drupalPost('admin/config/regional/date-time/locale/fr/edit', $edit, t('Save configuration'));
+    $this->assertText(t('Configuration saved.'), 'French date formats updated.');
+    $edit = array(
+      'date_format_long' => 'j M Y - g:ia',
+      'date_format_medium' => 'j M Y - g:ia',
+      'date_format_short' => 'j M Y - g:ia',
+    );
+    $this->drupalPost('admin/config/regional/date-time/locale/en/edit', $edit, t('Save configuration'));
+    $this->assertText(t('Configuration saved.'), 'English date formats updated.');
+
+    // Create node content.
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+
+    // Configure format for the node posted date changes with the language.
+    $this->drupalGet('node/' . $node->nid);
+    $english_date = format_date($node->created, 'custom', 'j M Y');
+    $this->assertText($english_date, t('English date format appears'));
+    $this->drupalGet('fr/node/' . $node->nid);
+    $french_date = format_date($node->created, 'custom', 'd.m.Y');
+    $this->assertText($french_date, t('French date format appears'));
+  }
+}
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleExportTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleExportTest.php
new file mode 100644
index 0000000..4ad9356
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleExportTest.php
@@ -0,0 +1,152 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\locale\Tests\LocaleExportTest.
+ */
+
+namespace Drupal\locale\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests for the export of translation files.
+ */
+class LocaleExportTest extends WebTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Translation export',
+      'description' => 'Tests the exportation of locale files.',
+      'group' => 'Locale',
+    );
+  }
+
+  /**
+   * A user able to create languages and export translations.
+   */
+  protected $admin_user = NULL;
+
+  function setUp() {
+    parent::setUp('locale');
+
+    $this->admin_user = $this->drupalCreateUser(array('administer languages', 'translate interface', 'access administration pages'));
+    $this->drupalLogin($this->admin_user);
+  }
+
+  /**
+   * Test exportation of translations.
+   */
+  function testExportTranslation() {
+    // First import some known translations.
+    // This will also automatically enable the 'fr' language.
+    $name = tempnam('temporary://', "po_") . '.po';
+    file_put_contents($name, $this->getPoFile());
+    $this->drupalPost('admin/config/regional/translate/import', array(
+      'langcode' => 'fr',
+      'files[file]' => $name,
+    ), t('Import'));
+    drupal_unlink($name);
+
+    // Get the French translations.
+    $this->drupalPost('admin/config/regional/translate/export', array(
+      'langcode' => 'fr',
+    ), t('Export'));
+
+    // Ensure we have a translation file.
+    $this->assertRaw('# French translation of Drupal', t('Exported French translation file.'));
+    // Ensure our imported translations exist in the file.
+    $this->assertRaw('msgstr "lundi"', t('French translations present in exported file.'));
+
+    // Import some more French translations which will be marked as customized.
+    $name = tempnam('temporary://', "po2_") . '.po';
+    file_put_contents($name, $this->getCustomPoFile());
+    $this->drupalPost('admin/config/regional/translate/import', array(
+      'langcode' => 'fr',
+      'files[file]' => $name,
+      'customized' => 1,
+    ), t('Import'));
+    drupal_unlink($name);
+
+    // We can't import a string with an empty translation, but calling
+    // locale() for an new string creates an entry in the locales_source table.
+    locale('February', NULL, 'fr');
+
+    // Export only customized French translations.
+    $this->drupalPost('admin/config/regional/translate/export', array(
+      'langcode' => 'fr',
+      'content_options[not_customized]' => FALSE,
+      'content_options[customized]' => TRUE,
+      'content_options[not_translated]' => FALSE,
+    ), t('Export'));
+
+    // Ensure we have a translation file.
+    $this->assertRaw('# French translation of Drupal', t('Exported French translation file with only customized strings.'));
+    // Ensure the customized translations exist in the file.
+    $this->assertRaw('msgstr "janvier"', t('French custom translation present in exported file.'));
+    // Ensure no untranslated strings exist in the file.
+    $this->assertNoRaw('msgid "February"', t('Untranslated string not present in exported file.'));
+
+    // Export only untranslated French translations.
+    $this->drupalPost('admin/config/regional/translate/export', array(
+      'langcode' => 'fr',
+      'content_options[not_customized]' => FALSE,
+      'content_options[customized]' => FALSE,
+      'content_options[not_translated]' => TRUE,
+    ), t('Export'));
+
+    // Ensure we have a translation file.
+    $this->assertRaw('# French translation of Drupal', t('Exported French translation file with only untranslated strings.'));
+    // Ensure no customized translations exist in the file.
+    $this->assertNoRaw('msgstr "janvier"', t('French custom translation not present in exported file.'));
+    // Ensure the untranslated strings exist in the file.
+    $this->assertRaw('msgid "February"', t('Untranslated string present in exported file.'));
+  }
+
+  /**
+   * Test exportation of translation template file.
+   */
+  function testExportTranslationTemplateFile() {
+    // Get the translation template file.
+    $this->drupalPost('admin/config/regional/translate/export', array(), t('Export'));
+    // Ensure we have a translation file.
+    $this->assertRaw('# LANGUAGE translation of PROJECT', t('Exported translation template file.'));
+  }
+
+  /**
+   * Helper function that returns a proper .po file.
+   */
+  function getPoFile() {
+    return <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 8\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
+
+msgid "Monday"
+msgstr "lundi"
+EOF;
+  }
+
+  /**
+   * Helper function that returns a .po file which strings will be marked
+   * as customized.
+   */
+  function getCustomPoFile() {
+    return <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 8\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
+
+msgid "January"
+msgstr "janvier"
+EOF;
+  }
+
+}
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleImportFunctionalTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleImportFunctionalTest.php
new file mode 100644
index 0000000..3beee64
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleImportFunctionalTest.php
@@ -0,0 +1,487 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\locale\Tests\LocaleImportFunctionalTest.
+ */
+
+namespace Drupal\locale\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Functional tests for the import of translation files.
+ */
+class LocaleImportFunctionalTest extends WebTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Translation import',
+      'description' => 'Tests the import of locale files.',
+      'group' => 'Locale',
+    );
+  }
+
+  /**
+   * A user able to create languages and import translations.
+   */
+  protected $admin_user = NULL;
+
+  function setUp() {
+    parent::setUp(array('locale', 'dblog'));
+
+    // Set the translation file directory.
+    variable_set('locale_translate_file_directory', drupal_get_path('module', 'locale') . '/tests');
+
+    $this->admin_user = $this->drupalCreateUser(array('administer languages', 'translate interface', 'access administration pages'));
+    $this->drupalLogin($this->admin_user);
+  }
+
+  /**
+   * Test import of standalone .po files.
+   */
+  function testStandalonePoFile() {
+    // Try importing a .po file.
+    $this->importPoFile($this->getPoFile(), array(
+      'langcode' => 'fr',
+    ));
+
+    // The import should automatically create the corresponding language.
+    $this->assertRaw(t('The language %language has been created.', array('%language' => 'French')), t('The language has been automatically created.'));
+
+    // The import should have created 8 strings.
+    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 8, '%update' => 0, '%delete' => 0)), t('The translation file was successfully imported.'));
+
+    // This import should have saved plural forms to have 2 variants.
+    $locale_plurals = variable_get('locale_translation_plurals', array());
+    $this->assert($locale_plurals['fr']['plurals'] == 2, t('Plural number initialized.'));
+
+    // Ensure we were redirected correctly.
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/translate', array('absolute' => TRUE)), t('Correct page redirection.'));
+
+
+    // Try importing a .po file with invalid tags.
+    $this->importPoFile($this->getBadPoFile(), array(
+      'langcode' => 'fr',
+    ));
+
+    // The import should have created 1 string and rejected 2.
+    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 1, '%update' => 0, '%delete' => 0)), t('The translation file was successfully imported.'));
+    $skip_message = format_plural(2, 'A translation string was skipped because of disallowed or malformed HTML. <a href="@url">See the log</a> for details.', '@count translation strings were skipped because of disallowed or malformed HTML. <a href="@url">See the log</a> for details.', array('@url' => url('admin/reports/dblog')));
+    $this->assertRaw($skip_message, t('Unsafe strings were skipped.'));
+
+
+    // Try importing a .po file which doesn't exist.
+    $name = $this->randomName(16);
+    $this->drupalPost('admin/config/regional/translate/import', array(
+      'langcode' => 'fr',
+      'files[file]' => $name,
+    ), t('Import'));
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/import', array('absolute' => TRUE)), t('Correct page redirection.'));
+    $this->assertText(t('File to import not found.'), t('File to import not found message.'));
+
+
+    // Try importing a .po file with overriding strings, and ensure existing
+    // strings are kept.
+    $this->importPoFile($this->getOverwritePoFile(), array(
+      'langcode' => 'fr',
+    ));
+
+    // The import should have created 1 string.
+    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 1, '%update' => 0, '%delete' => 0)), t('The translation file was successfully imported.'));
+    // Ensure string wasn't overwritten.
+    $search = array(
+      'string' => 'Montag',
+      'language' => 'fr',
+      'translation' => 'translated',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    $this->assertText(t('No strings available.'), t('String not overwritten by imported string.'));
+
+    // This import should not have changed number of plural forms.
+    $locale_plurals = variable_get('locale_translation_plurals', array());
+    $this->assert($locale_plurals['fr']['plurals'] == 2, t('Plural numbers untouched.'));
+
+    // Try importing a .po file with overriding strings, and ensure existing
+    // strings are overwritten.
+    $this->importPoFile($this->getOverwritePoFile(), array(
+      'langcode' => 'fr',
+      'overwrite_options[not_customized]' => TRUE,
+    ));
+
+    // The import should have updated 2 strings.
+    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 0, '%update' => 2, '%delete' => 0)), t('The translation file was successfully imported.'));
+    // Ensure string was overwritten.
+    $search = array(
+      'string' => 'Montag',
+      'language' => 'fr',
+      'translation' => 'translated',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    $this->assertNoText(t('No strings available.'), t('String overwritten by imported string.'));
+    // This import should have changed number of plural forms.
+    $locale_plurals = variable_get('locale_translation_plurals', array());
+    $this->assert($locale_plurals['fr']['plurals'] == 3, t('Plural numbers changed.'));
+
+    // Importing a .po file and mark its strings as customized strings.
+    $this->importPoFile($this->getCustomPoFile(), array(
+      'langcode' => 'fr',
+      'customized' => TRUE,
+    ));
+
+    // The import should have created 6 strings.
+    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 6, '%update' => 0, '%delete' => 0)), t('The customized translation file was successfully imported.'));
+
+    // The database should now contain 6 customized strings (two imported
+    // strings are not translated).
+    $count = db_query('SELECT lid FROM {locales_target} WHERE customized = :custom', array(':custom' => 1))->rowCount();
+    $this->assertEqual($count, 6, t('Customized translations succesfully imported.'));
+
+    // Try importing a .po file with overriding strings, and ensure existing
+    // customized strings are kept.
+    $this->importPoFile($this->getCustomOverwritePoFile(), array(
+      'langcode' => 'fr',
+      'overwrite_options[not_customized]' => TRUE,
+      'overwrite_options[customized]' => FALSE,
+    ));
+
+    // The import should have created 1 string.
+    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 1, '%update' => 0, '%delete' => 0)), t('The customized translation file was successfully imported.'));
+    // Ensure string wasn't overwritten.
+    $search = array(
+      'string' => 'januari',
+      'language' => 'fr',
+      'translation' => 'translated',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    $this->assertText(t('No strings available.'), t('Customized string not overwritten by imported string.'));
+
+    // Try importing a .po file with overriding strings, and ensure existing
+    // customized strings are overwritten.
+    $this->importPoFile($this->getCustomOverwritePoFile(), array(
+      'langcode' => 'fr',
+      'overwrite_options[not_customized]' => FALSE,
+      'overwrite_options[customized]' => TRUE,
+    ));
+
+    // The import should have updated 2 strings.
+    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 0, '%update' => 2, '%delete' => 0)), t('The customized translation file was successfully imported.'));
+    // Ensure string was overwritten.
+    $search = array(
+      'string' => 'januari',
+      'language' => 'fr',
+      'translation' => 'translated',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    $this->assertNoText(t('No strings available.'), t('Customized string overwritten by imported string.'));
+
+  }
+
+  /**
+   * Test automatic import of a module's translation files.
+   */
+  function testAutomaticModuleTranslationImportLanguageEnable() {
+    // Code for the language - manually set to match the test translation file.
+    $langcode = 'xx';
+    // The English name for the language.
+    $name = $this->randomName(16);
+
+    // Create a custom language.
+    $edit = array(
+      'predefined_langcode' => 'custom',
+      'langcode' => $langcode,
+      'name' => $name,
+      'direction' => '0',
+    );
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
+
+    // Ensure the translation file was automatically imported when language was
+    // added.
+    $this->assertText(t('One translation file imported.'), t('Language file automatically imported.'));
+
+    // Ensure strings were successfully imported.
+    $search = array(
+      'string' => 'lundi',
+      'language' => $langcode,
+      'translation' => 'translated',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    $this->assertNoText(t('No strings available.'), t('String successfully imported.'));
+  }
+
+  /**
+   * Test msgctxt context support.
+   */
+  function testLanguageContext() {
+    // Try importing a .po file.
+    $this->importPoFile($this->getPoFileWithContext(), array(
+      'langcode' => 'hr',
+    ));
+
+    $this->assertIdentical(t('May', array(), array('langcode' => 'hr', 'context' => 'Long month name')), 'Svibanj', t('Long month name context is working.'));
+    $this->assertIdentical(t('May', array(), array('langcode' => 'hr')), 'Svi.', t('Default context is working.'));
+  }
+
+  /**
+   * Test empty msgstr at end of .po file see #611786.
+   */
+  function testEmptyMsgstr() {
+    $langcode = 'hu';
+
+    // Try importing a .po file.
+    $this->importPoFile($this->getPoFileWithMsgstr(), array(
+      'langcode' => $langcode,
+    ));
+
+    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 1, '%update' => 0, '%delete' => 0)), t('The translation file was successfully imported.'));
+    $this->assertIdentical(t('Operations', array(), array('langcode' => $langcode)), 'Műveletek', t('String imported and translated.'));
+
+    // Try importing a .po file.
+    $this->importPoFile($this->getPoFileWithEmptyMsgstr(), array(
+      'langcode' => $langcode,
+      'overwrite_options[not_customized]' => TRUE,
+    ));
+    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 0, '%update' => 0, '%delete' => 1)), t('The translation file was successfully imported.'));
+    // This is the language indicator on the translation search screen for
+    // untranslated strings.
+    $language_indicator = "<em class=\"locale-untranslated\">$langcode</em> ";
+    $str = "Operations";
+    $search = array(
+      'string' => $str,
+      'language' => 'all',
+      'translation' => 'all',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    // assertText() seems to remove the input field where $str always could be
+    // found, so this is not a false assert.
+    $this->assertText($str, t('Search found the string.'));
+    $this->assertRaw($language_indicator, t('String is untranslated again.'));
+  }
+
+  /**
+   * Helper function: import a standalone .po file in a given language.
+   *
+   * @param $contents
+   *   Contents of the .po file to import.
+   * @param $options
+   *   Additional options to pass to the translation import form.
+   */
+  function importPoFile($contents, array $options = array()) {
+    $name = tempnam('temporary://', "po_") . '.po';
+    file_put_contents($name, $contents);
+    $options['files[file]'] = $name;
+    $this->drupalPost('admin/config/regional/translate/import', $options, t('Import'));
+    drupal_unlink($name);
+  }
+
+  /**
+   * Helper function that returns a proper .po file.
+   */
+  function getPoFile() {
+    return <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 8\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
+
+msgid "One sheep"
+msgid_plural "@count sheep"
+msgstr[0] "un mouton"
+msgstr[1] "@count moutons"
+
+msgid "Monday"
+msgstr "lundi"
+
+msgid "Tuesday"
+msgstr "mardi"
+
+msgid "Wednesday"
+msgstr "mercredi"
+
+msgid "Thursday"
+msgstr "jeudi"
+
+msgid "Friday"
+msgstr "vendredi"
+
+msgid "Saturday"
+msgstr "samedi"
+
+msgid "Sunday"
+msgstr "dimanche"
+EOF;
+  }
+
+  /**
+   * Helper function that returns a bad .po file.
+   */
+  function getBadPoFile() {
+    return <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 8\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
+
+msgid "Save configuration"
+msgstr "Enregistrer la configuration"
+
+msgid "edit"
+msgstr "modifier<img SRC="javascript:alert(\'xss\');">"
+
+msgid "delete"
+msgstr "supprimer<script>alert('xss');</script>"
+
+EOF;
+  }
+
+  /**
+   * Helper function that returns a proper .po file for testing.
+   */
+  function getOverwritePoFile() {
+    return <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 8\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\\n"
+
+msgid "Monday"
+msgstr "Montag"
+
+msgid "Day"
+msgstr "Jour"
+EOF;
+  }
+
+  /**
+   * Helper function that returns a .po file which strings will be marked
+   * as customized.
+   */
+  function getCustomPoFile() {
+    return <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 8\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
+
+msgid "One dog"
+msgid_plural "@count dogs"
+msgstr[0] "un chien"
+msgstr[1] "@count chiens"
+
+msgid "January"
+msgstr "janvier"
+
+msgid "February"
+msgstr "février"
+
+msgid "March"
+msgstr "mars"
+
+msgid "April"
+msgstr "avril"
+
+msgid "June"
+msgstr "juin"
+EOF;
+  }
+
+  /**
+   * Helper function that returns a .po file for testing customized strings.
+   */
+  function getCustomOverwritePoFile() {
+    return <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 8\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
+
+msgid "January"
+msgstr "januari"
+
+msgid "February"
+msgstr "februari"
+
+msgid "July"
+msgstr "juillet"
+EOF;
+  }
+
+  /**
+   * Helper function that returns a .po file with context.
+   */
+  function getPoFileWithContext() {
+    // Croatian (code hr) is one the the languages that have a different
+    // form for the full name and the abbreviated name for the month May.
+    return <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 8\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\\n"
+
+msgctxt "Long month name"
+msgid "May"
+msgstr "Svibanj"
+
+msgid "May"
+msgstr "Svi."
+EOF;
+  }
+
+  /**
+   * Helper function that returns a .po file with an empty last item.
+   */
+  function getPoFileWithEmptyMsgstr() {
+    return <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 8\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
+
+msgid "Operations"
+msgstr ""
+
+EOF;
+  }
+  /**
+   * Helper function that returns a .po file with an empty last item.
+   */
+  function getPoFileWithMsgstr() {
+    return <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 8\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
+
+msgid "Operations"
+msgstr "Műveletek"
+
+msgid "Will not appear in Drupal core, so we can ensure the test passes"
+msgstr ""
+
+EOF;
+  }
+
+}
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleInstallTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleInstallTest.php
new file mode 100644
index 0000000..f1677eb
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleInstallTest.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\locale\Tests\LocaleInstallTest.
+ */
+
+namespace Drupal\locale\Tests;
+
+use Drupal\simpletest\WebTestBase;
+use ReflectionFunction;
+
+/**
+ * Tests for the st() function.
+ */
+class LocaleInstallTest extends WebTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'String translation using st()',
+      'description' => 'Tests that st() works like t().',
+      'group' => 'Locale',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('locale');
+
+    // st() lives in install.inc, so ensure that it is loaded for all tests.
+    require_once DRUPAL_ROOT . '/core/includes/install.inc';
+  }
+
+  /**
+   * Verify that function signatures of t() and st() are equal.
+   */
+  function testFunctionSignatures() {
+    $reflector_t = new ReflectionFunction('t');
+    $reflector_st = new ReflectionFunction('st');
+    $this->assertEqual($reflector_t->getParameters(), $reflector_st->getParameters(), t('Function signatures of t() and st() are equal.'));
+  }
+}
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleJavascriptTranslation.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleJavascriptTranslation.php
new file mode 100644
index 0000000..9739537
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleJavascriptTranslation.php
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\locale\Tests\LocaleJavascriptTranslation.
+ */
+
+namespace Drupal\locale\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Functional tests for JavaScript parsing for translatable strings.
+ */
+class LocaleJavascriptTranslation extends WebTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Javascript translation',
+      'description' => 'Tests parsing js files for translatable strings',
+      'group' => 'Locale',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('locale');
+  }
+
+  function testFileParsing() {
+
+    $filename = drupal_get_path('module', 'locale') . '/tests/locale_test.js';
+
+    // Parse the file to look for source strings.
+    _locale_parse_js_file($filename);
+
+    // Get all of the source strings that were found.
+    $source_strings = db_select('locales_source', 's')
+      ->fields('s', array('source', 'context'))
+      ->condition('s.location', $filename)
+      ->execute()
+      ->fetchAllKeyed();
+
+    // List of all strings that should be in the file.
+    $test_strings = array(
+      "Standard Call t" => '',
+      "Whitespace Call t" => '',
+
+      "Single Quote t" => '',
+      "Single Quote \\'Escaped\\' t" => '',
+      "Single Quote Concat strings t" => '',
+
+      "Double Quote t" => '',
+      "Double Quote \\\"Escaped\\\" t" => '',
+      "Double Quote Concat strings t" => '',
+
+      "Context !key Args t" => "Context string",
+
+      "Context Unquoted t" => "Context string unquoted",
+      "Context Single Quoted t" => "Context string single quoted",
+      "Context Double Quoted t" => "Context string double quoted",
+
+      "Standard Call plural" => '',
+      "Standard Call @count plural" => '',
+      "Whitespace Call plural" => '',
+      "Whitespace Call @count plural" => '',
+
+      "Single Quote plural" => '',
+      "Single Quote @count plural" => '',
+      "Single Quote \\'Escaped\\' plural" => '',
+      "Single Quote \\'Escaped\\' @count plural" => '',
+
+      "Double Quote plural" => '',
+      "Double Quote @count plural" => '',
+      "Double Quote \\\"Escaped\\\" plural" => '',
+      "Double Quote \\\"Escaped\\\" @count plural" => '',
+
+      "Context !key Args plural" => "Context string",
+      "Context !key Args @count plural" => "Context string",
+
+      "Context Unquoted plural" => "Context string unquoted",
+      "Context Unquoted @count plural" => "Context string unquoted",
+      "Context Single Quoted plural" => "Context string single quoted",
+      "Context Single Quoted @count plural" => "Context string single quoted",
+      "Context Double Quoted plural" => "Context string double quoted",
+      "Context Double Quoted @count plural" => "Context string double quoted",
+    );
+
+    // Assert that all strings were found properly.
+    foreach ($test_strings as $str => $context) {
+      $args = array('%source' => $str, '%context' => $context);
+
+      // Make sure that the string was found in the file.
+      $this->assertTrue(isset($source_strings[$str]), t("Found source string: %source", $args));
+
+      // Make sure that the proper context was matched.
+      $this->assertTrue(isset($source_strings[$str]) && $source_strings[$str] === $context, strlen($context) > 0 ? t("Context for %source is %context", $args) : t("Context for %source is blank", $args));
+    }
+
+    $this->assertEqual(count($source_strings), count($test_strings), t("Found correct number of source strings."));
+  }
+}
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleMultilingualFieldsTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleMultilingualFieldsTest.php
new file mode 100644
index 0000000..2a8299a
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleMultilingualFieldsTest.php
@@ -0,0 +1,137 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\locale\Tests\LocaleMultilingualFieldsTest.
+ */
+
+namespace Drupal\locale\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Functional test for multilingual fields.
+ */
+class LocaleMultilingualFieldsTest extends WebTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Multilingual fields',
+      'description' => 'Test multilingual support for fields.',
+      'group' => 'Locale',
+    );
+  }
+
+  function setUp() {
+    parent::setUp(array('node', 'locale'));
+
+    // Create Basic page node type.
+    $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+
+    // Setup users.
+    $admin_user = $this->drupalCreateUser(array('administer languages', 'administer content types', 'access administration pages', 'create page content', 'edit own page content'));
+    $this->drupalLogin($admin_user);
+
+    // Add a new language.
+    $language = (object) array(
+      'langcode' => 'it',
+      'name' => 'Italian',
+    );
+    language_save($language);
+
+    // Enable URL language detection and selection.
+    $edit = array('language_interface[enabled][language-url]' => '1');
+    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
+
+    // Set "Basic page" content type to use multilingual support.
+    $edit = array(
+      'node_type_language' => 1,
+    );
+    $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
+    $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.'));
+
+    // Make node body translatable.
+    $field = field_info_field('body');
+    $field['translatable'] = TRUE;
+    field_update_field($field);
+  }
+
+  /**
+   * Test if field languages are correctly set through the node form.
+   */
+  function testMultilingualNodeForm() {
+    // Create "Basic page" content.
+    $langcode = LANGUAGE_NOT_SPECIFIED;
+    $title_key = "title";
+    $title_value = $this->randomName(8);
+    $body_key = "body[$langcode][0][value]";
+    $body_value = $this->randomName(16);
+
+    // Create node to edit.
+    $edit = array();
+    $edit[$title_key] = $title_value;
+    $edit[$body_key] = $body_value;
+    $edit['langcode'] = 'en';
+    $this->drupalPost('node/add/page', $edit, t('Save'));
+
+    // Check that the node exists in the database.
+    $node = $this->drupalGetNodeByTitle($edit[$title_key]);
+    $this->assertTrue($node, t('Node found in database.'));
+
+    $assert = isset($node->body['en']) && !isset($node->body[LANGUAGE_NOT_SPECIFIED]) && $node->body['en'][0]['value'] == $body_value;
+    $this->assertTrue($assert, t('Field language correctly set.'));
+
+    // Change node language.
+    $this->drupalGet("node/$node->nid/edit");
+    $edit = array(
+      $title_key => $this->randomName(8),
+      'langcode' => 'it'
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $node = $this->drupalGetNodeByTitle($edit[$title_key]);
+    $this->assertTrue($node, t('Node found in database.'));
+
+    $assert = isset($node->body['it']) && !isset($node->body['en']) && $node->body['it'][0]['value'] == $body_value;
+    $this->assertTrue($assert, t('Field language correctly changed.'));
+
+    // Enable content language URL detection.
+    language_negotiation_set(LANGUAGE_TYPE_CONTENT, array(LANGUAGE_NEGOTIATION_URL => 0));
+
+    // Test multilingual field language fallback logic.
+    $this->drupalGet("it/node/$node->nid");
+    $this->assertRaw($body_value, t('Body correctly displayed using Italian as requested language'));
+
+    $this->drupalGet("node/$node->nid");
+    $this->assertRaw($body_value, t('Body correctly displayed using English as requested language'));
+  }
+
+  /*
+   * Test multilingual field display settings.
+   */
+  function testMultilingualDisplaySettings() {
+    // Create "Basic page" content.
+    $langcode = LANGUAGE_NOT_SPECIFIED;
+    $title_key = "title";
+    $title_value = $this->randomName(8);
+    $body_key = "body[$langcode][0][value]";
+    $body_value = $this->randomName(16);
+
+    // Create node to edit.
+    $edit = array();
+    $edit[$title_key] = $title_value;
+    $edit[$body_key] = $body_value;
+    $edit['langcode'] = 'en';
+    $this->drupalPost('node/add/page', $edit, t('Save'));
+
+    // Check that the node exists in the database.
+    $node = $this->drupalGetNodeByTitle($edit[$title_key]);
+    $this->assertTrue($node, t('Node found in database.'));
+
+    // Check if node body is showed.
+    $this->drupalGet("node/$node->nid");
+    $body = $this->xpath('//article[@id=:id]//div[@class=:class]/descendant::p', array(
+      ':id' => 'node-' . $node->nid,
+      ':class' => 'content',
+    ));
+    $this->assertEqual(current($body), $node->body['en'][0]['value'], 'Node body found.');
+  }
+}
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocalePathTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocalePathTest.php
new file mode 100644
index 0000000..61fd67f
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocalePathTest.php
@@ -0,0 +1,149 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\locale\Tests\LocalePathTest.
+ */
+
+namespace Drupal\locale\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Functional tests for configuring a different path alias per language.
+ */
+class LocalePathTest extends WebTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Path language settings',
+      'description' => 'Checks you can configure a language for individual url aliases.',
+      'group' => 'Locale',
+    );
+  }
+
+  function setUp() {
+    parent::setUp(array('node', 'locale', 'path'));
+
+    $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+    variable_set('site_frontpage', 'node');
+  }
+
+  /**
+   * Test if a language can be associated with a path alias.
+   */
+  function testPathLanguageConfiguration() {
+    global $base_url;
+
+    // User to add and remove language.
+    $admin_user = $this->drupalCreateUser(array('administer languages', 'create page content', 'administer url aliases', 'create url aliases', 'access administration pages'));
+
+    // Add custom language.
+    $this->drupalLogin($admin_user);
+    // Code for the language.
+    $langcode = 'xx';
+    // The English name for the language.
+    $name = $this->randomName(16);
+    // The domain prefix.
+    $prefix = $langcode;
+    $edit = array(
+      'predefined_langcode' => 'custom',
+      'langcode' => $langcode,
+      'name' => $name,
+      'direction' => '0',
+    );
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
+
+    // Set path prefix.
+    $edit = array( "prefix[$langcode]" => $prefix );
+    $this->drupalPost('admin/config/regional/language/detection/url', $edit, t('Save configuration'));
+
+    // Check that the "xx" front page is readily available because path prefix
+    // negotiation is pre-configured.
+    $this->drupalGet($prefix);
+    $this->assertText(t('Welcome to Drupal'), t('The "xx" front page is readibly available.'));
+
+    // Create a node.
+    $node = $this->drupalCreateNode(array('type' => 'page'));
+
+    // Create a path alias in default language (English).
+    $path = 'admin/config/search/path/add';
+    $english_path = $this->randomName(8);
+    $edit = array(
+      'source'   => 'node/' . $node->nid,
+      'alias'    => $english_path,
+      'langcode' => 'en',
+    );
+    $this->drupalPost($path, $edit, t('Save'));
+
+    // Create a path alias in new custom language.
+    $custom_language_path = $this->randomName(8);
+    $edit = array(
+      'source'   => 'node/' . $node->nid,
+      'alias'    => $custom_language_path,
+      'langcode' => $langcode,
+    );
+    $this->drupalPost($path, $edit, t('Save'));
+
+    // Confirm English language path alias works.
+    $this->drupalGet($english_path);
+    $this->assertText($node->title, t('English alias works.'));
+
+    // Confirm custom language path alias works.
+    $this->drupalGet($prefix . '/' . $custom_language_path);
+    $this->assertText($node->title, t('Custom language alias works.'));
+
+    // Create a custom path.
+    $custom_path = $this->randomName(8);
+
+    // Check priority of language for alias by source path.
+    $edit = array(
+      'source'   => 'node/' . $node->nid,
+      'alias'    => $custom_path,
+      'langcode' => LANGUAGE_NOT_SPECIFIED,
+    );
+    path_save($edit);
+    $lookup_path = drupal_lookup_path('alias', 'node/' . $node->nid, 'en');
+    $this->assertEqual($english_path, $lookup_path, t('English language alias has priority.'));
+    // Same check for language 'xx'.
+    $lookup_path = drupal_lookup_path('alias', 'node/' . $node->nid, $prefix);
+    $this->assertEqual($custom_language_path, $lookup_path, t('Custom language alias has priority.'));
+    path_delete($edit);
+
+    // Create language nodes to check priority of aliases.
+    $first_node = $this->drupalCreateNode(array('type' => 'page', 'promote' => 1));
+    $second_node = $this->drupalCreateNode(array('type' => 'page', 'promote' => 1));
+
+    // Assign a custom path alias to the first node with the English language.
+    $edit = array(
+      'source'   => 'node/' . $first_node->nid,
+      'alias'    => $custom_path,
+      'langcode' => 'en',
+    );
+    path_save($edit);
+
+    // Assign a custom path alias to second node with LANGUAGE_NOT_SPECIFIED.
+    $edit = array(
+      'source'   => 'node/' . $second_node->nid,
+      'alias'    => $custom_path,
+      'langcode' => LANGUAGE_NOT_SPECIFIED,
+    );
+    path_save($edit);
+
+    // Test that both node titles link to our path alias.
+    $this->drupalGet('<front>');
+    $custom_path_url = base_path() . $GLOBALS['script_path'] . $custom_path;
+    $elements = $this->xpath('//a[@href=:href and .=:title]', array(':href' => $custom_path_url, ':title' => $first_node->title));
+    $this->assertTrue(!empty($elements), t('First node links to the path alias.'));
+    $elements = $this->xpath('//a[@href=:href and .=:title]', array(':href' => $custom_path_url, ':title' => $second_node->title));
+    $this->assertTrue(!empty($elements), t('Second node links to the path alias.'));
+
+    // Confirm that the custom path leads to the first node.
+    $this->drupalGet($custom_path);
+    $this->assertText($first_node->title, t('Custom alias returns first node.'));
+
+    // Confirm that the custom path with prefix leads to the second node.
+    $this->drupalGet($prefix . '/' . $custom_path);
+    $this->assertText($second_node->title, t('Custom alias with prefix returns second node.'));
+
+  }
+}
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocalePluralFormatTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocalePluralFormatTest.php
new file mode 100644
index 0000000..6d45d21
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocalePluralFormatTest.php
@@ -0,0 +1,323 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\locale\Tests\LocalePluralFormatTest.
+ */
+
+namespace Drupal\locale\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests plural format handling functionality.
+ */
+class LocalePluralFormatTest extends WebTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Plural handling',
+      'description' => 'Tests plural handling for various languages.',
+      'group' => 'Locale',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('locale');
+
+    $admin_user = $this->drupalCreateUser(array('administer languages', 'translate interface', 'access administration pages'));
+    $this->drupalLogin($admin_user);
+  }
+
+  /**
+   * Tests locale_get_plural() and format_plural() functionality.
+   */
+  function testGetPluralFormat() {
+    // Import some .po files with formulas to set up the environment.
+    // These will also add the languages to the system and enable them.
+    $this->importPoFile($this->getPoFileWithSimplePlural(), array(
+      'langcode' => 'fr',
+    ));
+    $this->importPoFile($this->getPoFileWithComplexPlural(), array(
+      'langcode' => 'hr',
+    ));
+
+    // Attempt to import some broken .po files as well to prove that these
+    // will not overwrite the proper plural formula imported above.
+    $this->importPoFile($this->getPoFileWithMissingPlural(), array(
+      'langcode' => 'fr',
+      'overwrite_options[not_customized]' => TRUE,
+    ));
+    $this->importPoFile($this->getPoFileWithBrokenPlural(), array(
+      'langcode' => 'hr',
+      'overwrite_options[not_customized]' => TRUE,
+    ));
+
+    // Reset static caches from locale_get_plural() to ensure we get fresh data.
+    drupal_static_reset('locale_get_plural');
+    drupal_static_reset('locale_get_plural:plurals');
+    drupal_static_reset('locale');
+
+    // Expected plural translation strings for each plural index.
+    $plural_strings = array(
+      // English is not imported in this case, so we assume built-in text
+      // and formulas.
+      'en' => array(
+        0 => '1 hour',
+        1 => '@count hours',
+      ),
+      'fr' => array(
+        0 => '1 heure',
+        1 => '@count heures',
+      ),
+      'hr' => array(
+        0 => '@count sat',
+        1 => '@count sata',
+        2 => '@count sati',
+      ),
+      // Hungarian is not imported, so it should assume the same text as
+      // English, but it will always pick the plural form as per the built-in
+      // logic, so only index -1 is relevant with the plural value.
+      'hu' => array(
+        0 => '1 hour',
+        -1 => '@count hours',
+      ),
+    );
+
+    // Expected plural indexes precomputed base on the plural formulas with
+    // given $count value.
+    $plural_tests = array(
+      'en' => array(
+        1 => 0,
+        0 => 1,
+        5 => 1,
+      ),
+      'fr' => array(
+        1 => 0,
+        0 => 0,
+        5 => 1,
+      ),
+      'hr' => array(
+        1 => 0,
+        21 => 0,
+        0 => 2,
+        2 => 1,
+        8 => 2,
+      ),
+      'hu' => array(
+        1 => -1,
+        21 => -1,
+        0 => -1,
+      ),
+    );
+
+    foreach ($plural_tests as $langcode => $tests) {
+      foreach ($tests as $count => $expected_plural_index) {
+        // Assert that the we get the right plural index.
+        $this->assertIdentical(locale_get_plural($count, $langcode), $expected_plural_index, 'Computed plural index for ' . $langcode . ' for count ' . $count . ' is ' . $expected_plural_index);
+        // Assert that the we get the right translation for that. Change the
+        // expected index as per the logic for translation lookups.
+        $expected_plural_index = ($count == 1) ? 0 : $expected_plural_index;
+        $expected_plural_string = str_replace('@count', $count, $plural_strings[$langcode][$expected_plural_index]);
+        $this->assertIdentical(format_plural($count, '1 hour', '@count hours', array(), array('langcode' => $langcode)), $expected_plural_string, 'Plural translation of 1 hours / @count hours for count ' . $count . ' in ' . $langcode . ' is ' . $expected_plural_string);
+      }
+    }
+  }
+
+  /**
+   * Tests plural editing and export functionality.
+   */
+  function testPluralEditExport() {
+    // Import some .po files with formulas to set up the environment.
+    // These will also add the languages to the system and enable them.
+    $this->importPoFile($this->getPoFileWithSimplePlural(), array(
+      'langcode' => 'fr',
+    ));
+    $this->importPoFile($this->getPoFileWithComplexPlural(), array(
+      'langcode' => 'hr',
+    ));
+
+    // Get the French translations.
+    $this->drupalPost('admin/config/regional/translate/export', array(
+      'langcode' => 'fr',
+    ), t('Export'));
+    // Ensure we have a translation file.
+    $this->assertRaw('# French translation of Drupal', t('Exported French translation file.'));
+    // Ensure our imported translations exist in the file.
+    $this->assertRaw("msgid \"Monday\"\nmsgstr \"lundi\"", t('French translations present in exported file.'));
+    // Check for plural export specifically.
+    $this->assertRaw("msgid \"1 hour\"\nmsgid_plural \"@count hours\"\nmsgstr[0] \"1 heure\"\nmsgstr[1] \"@count heures\"", t('Plural translations exported properly.'));
+
+    // Get the Croatian translations.
+    $this->drupalPost('admin/config/regional/translate/export', array(
+      'langcode' => 'hr',
+    ), t('Export'));
+    // Ensure we have a translation file.
+    $this->assertRaw('# Croatian translation of Drupal', t('Exported Croatian translation file.'));
+    // Ensure our imported translations exist in the file.
+    $this->assertRaw("msgid \"Monday\"\nmsgstr \"Ponedjeljak\"", t('Croatian translations present in exported file.'));
+    // Check for plural export specifically.
+    $this->assertRaw("msgid \"1 hour\"\nmsgid_plural \"@count hours\"\nmsgstr[0] \"@count sat\"\nmsgstr[1] \"@count sata\"\nmsgstr[2] \"@count sati\"", t('Plural translations exported properly.'));
+
+    // Check if the source appears on the translation page.
+    $this->drupalGet('admin/config/regional/translate');
+    $this->assertText("1 hour, @count hours");
+
+    // Look up editing page for this plural string and check fields.
+    $lid = db_query("SELECT lid FROM {locales_source} WHERE source = :source AND context = ''", array(':source' => "1 hour" . LOCALE_PLURAL_DELIMITER . "@count hours"))->fetchField();
+    $path = 'admin/config/regional/translate/edit/' . $lid;
+    $this->drupalGet($path);
+    // Labels for plural editing elements.
+    $this->assertText('Singular form');
+    $this->assertText('First plural form');
+    $this->assertText('2. plural form');
+    // Plural values for both languages.
+    $this->assertFieldById('edit-translations-hr-0', '@count sat');
+    $this->assertFieldById('edit-translations-hr-1', '@count sata');
+    $this->assertFieldById('edit-translations-hr-2', '@count sati');
+    $this->assertNoFieldById('edit-translations-hr-3');
+    $this->assertFieldById('edit-translations-fr-0', '1 heure');
+    $this->assertFieldById('edit-translations-fr-1', '@count heures');
+    $this->assertNoFieldById('edit-translations-fr-2');
+
+    // Edit some translations and see if that took effect.
+    $edit = array(
+      'translations[fr][0]' => '1 heure edited',
+      'translations[hr][1]' => '@count sata edited',
+    );
+    $this->drupalPost($path, $edit, t('Save translations'));
+
+    // Inject a plural source string to the database. We need to use a specific
+    // langcode here because the language will be English by default and will
+    // not save our source string for performance optimization if we do not ask
+    // specifically for a language.
+    format_plural(1, '1 day', '@count days', array(), array('langcode' => 'fr'));
+    // Look up editing page for this plural string and check fields.
+    $lid = db_query("SELECT lid FROM {locales_source} WHERE source = :source AND context = ''", array(':source' => "1 day" . LOCALE_PLURAL_DELIMITER . "@count days"))->fetchField();
+    $path = 'admin/config/regional/translate/edit/' . $lid;
+
+    // Save complete translations for the string in both languages.
+    $edit = array(
+      'translations[fr][0]' => '1 jour',
+      'translations[fr][1]' => '@count jours',
+      'translations[hr][0]' => '@count dan',
+      'translations[hr][1]' => '@count dana',
+      'translations[hr][2]' => '@count dana',
+    );
+    $this->drupalPost($path, $edit, t('Save translations'));
+
+    // Get the French translations.
+    $this->drupalPost('admin/config/regional/translate/export', array(
+      'langcode' => 'fr',
+    ), t('Export'));
+    // Check for plural export specifically.
+    $this->assertRaw("msgid \"1 hour\"\nmsgid_plural \"@count hours\"\nmsgstr[0] \"1 heure edited\"\nmsgstr[1] \"@count heures\"", t('Edited French plural translations for hours exported properly.'));
+    $this->assertRaw("msgid \"1 day\"\nmsgid_plural \"@count days\"\nmsgstr[0] \"1 jour\"\nmsgstr[1] \"@count jours\"", t('Added French plural translations for days exported properly.'));
+
+    // Get the Croatian translations.
+    $this->drupalPost('admin/config/regional/translate/export', array(
+      'langcode' => 'hr',
+    ), t('Export'));
+    // Check for plural export specifically.
+    $this->assertRaw("msgid \"1 hour\"\nmsgid_plural \"@count hours\"\nmsgstr[0] \"@count sat\"\nmsgstr[1] \"@count sata edited\"\nmsgstr[2] \"@count sati\"", t('Edited Croatian plural translations exported properly.'));
+    $this->assertRaw("msgid \"1 day\"\nmsgid_plural \"@count days\"\nmsgstr[0] \"@count dan\"\nmsgstr[1] \"@count dana\"\nmsgstr[2] \"@count dana\"", t('Added Croatian plural translations exported properly.'));
+  }
+
+
+  /**
+   * Imports a standalone .po file in a given language.
+   *
+   * @param $contents
+   *   Contents of the .po file to import.
+   * @param $options
+   *   Additional options to pass to the translation import form.
+   */
+  function importPoFile($contents, array $options = array()) {
+    $name = tempnam('temporary://', "po_") . '.po';
+    file_put_contents($name, $contents);
+    $options['files[file]'] = $name;
+    $this->drupalPost('admin/config/regional/translate/import', $options, t('Import'));
+    drupal_unlink($name);
+  }
+
+  /**
+   * Returns a .po file with a simple plural formula.
+   */
+  function getPoFileWithSimplePlural() {
+    return <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 8\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
+
+msgid "1 hour"
+msgid_plural "@count hours"
+msgstr[0] "1 heure"
+msgstr[1] "@count heures"
+
+msgid "Monday"
+msgstr "lundi"
+EOF;
+  }
+
+  /**
+   * Returns a .po file with a complex plural formula.
+   */
+  function getPoFileWithComplexPlural() {
+    return <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 8\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\\n"
+
+msgid "1 hour"
+msgid_plural "@count hours"
+msgstr[0] "@count sat"
+msgstr[1] "@count sata"
+msgstr[2] "@count sati"
+
+msgid "Monday"
+msgstr "Ponedjeljak"
+EOF;
+  }
+
+  /**
+   * Returns a .po file with a missing plural formula.
+   */
+  function getPoFileWithMissingPlural() {
+    return <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 8\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+
+msgid "Monday"
+msgstr "lundi"
+EOF;
+  }
+
+  /**
+   * Returns a .po file with a broken plural formula.
+   */
+  function getPoFileWithBrokenPlural() {
+    return <<< EOF
+msgid ""
+msgstr ""
+"Project-Id-Version: Drupal 8\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: broken, will not parse\\n"
+
+msgid "Monday"
+msgstr "Ponedjeljak"
+EOF;
+  }
+}
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php
new file mode 100644
index 0000000..28e0834
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php
@@ -0,0 +1,418 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\locale\Tests\LocaleTranslationTest.
+ */
+
+namespace Drupal\locale\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Functional test for string translation and validation.
+ */
+class LocaleTranslationTest extends WebTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'String translate, search and validate',
+      'description' => 'Adds a new locale and translates its name. Checks the validation of translation strings and search results.',
+      'group' => 'Locale',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('locale');
+  }
+
+  /**
+   * Adds a language and tests string translation by users with the appropriate permissions.
+   */
+  function testStringTranslation() {
+    global $base_url;
+
+    // User to add and remove language.
+    $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
+    // User to translate and delete string.
+    $translate_user = $this->drupalCreateUser(array('translate interface', 'access administration pages'));
+    // Code for the language.
+    $langcode = 'xx';
+    // The English name for the language. This will be translated.
+    $name = $this->randomName(16);
+    // This is the language indicator on the translation search screen for
+    // untranslated strings.
+    $language_indicator = "<em class=\"locale-untranslated\">$langcode</em> ";
+    // This will be the translation of $name.
+    $translation = $this->randomName(16);
+    $translation_to_en = $this->randomName(16);
+
+    // Add custom language.
+    $this->drupalLogin($admin_user);
+    $edit = array(
+      'predefined_langcode' => 'custom',
+      'langcode' => $langcode,
+      'name' => $name,
+      'direction' => '0',
+    );
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
+    // Add string.
+    t($name, array(), array('langcode' => $langcode));
+    // Reset locale cache.
+    locale_reset();
+    $this->assertRaw('"edit-site-default-' . $langcode .'"', t('Language code found.'));
+    $this->assertText(t($name), t('Test language added.'));
+    $this->drupalLogout();
+
+    // Search for the name and translate it.
+    $this->drupalLogin($translate_user);
+    $search = array(
+      'string' => $name,
+      'language' => 'all',
+      'translation' => 'all',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    // assertText() seems to remove the input field where $name always could be
+    // found, so this is not a false assert. See how assertNoText succeeds
+    // later.
+    $this->assertText($name, t('Search found the name.'));
+    $this->assertRaw($language_indicator, t('Name is untranslated.'));
+    // Assume this is the only result, given the random name.
+    $this->clickLink(t('edit'));
+    // We save the lid from the path.
+    $matches = array();
+    preg_match('!admin/config/regional/translate/edit/(\d+)!', $this->getUrl(), $matches);
+    $lid = $matches[1];
+    // No t() here, it's surely not translated yet.
+    $this->assertText($name, t('name found on edit screen.'));
+    $this->assertNoText('English', t('No way to translate the string to English.'));
+    $this->drupalLogout();
+    $this->drupalLogin($admin_user);
+    $this->drupalPost('admin/config/regional/language/edit/en', array('locale_translate_english' => TRUE), t('Save language'));
+    $this->drupalLogout();
+    $this->drupalLogin($translate_user);
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    // assertText() seems to remove the input field where $name always could be
+    // found, so this is not a false assert. See how assertNoText succeeds
+    // later.
+    $this->assertText($name, t('Search found the name.'));
+    $this->assertRaw($language_indicator, t('Name is untranslated.'));
+    // Assume this is the only result, given the random name.
+    $this->clickLink(t('edit'));
+    $string_edit_url = $this->getUrl();
+    $edit = array(
+      "translations[$langcode][0]" => $translation,
+      'translations[en][0]' => $translation_to_en,
+    );
+    $this->drupalPost(NULL, $edit, t('Save translations'));
+    $this->assertText(t('The string has been saved.'), t('The string has been saved.'));
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/translate', array('absolute' => TRUE)), t('Correct page redirection.'));
+    $this->drupalGet($string_edit_url);
+    $this->assertRaw($translation, t('Non-English translation properly saved.'));
+    $this->assertRaw($translation_to_en, t('English translation properly saved.'));
+    $this->assertTrue($name != $translation && t($name, array(), array('langcode' => $langcode)) == $translation, t('t() works for non-English.'));
+    // Refresh the locale() cache to get fresh data from t() below. We are in
+    // the same HTTP request and therefore t() is not refreshed by saving the
+    // translation above.
+    locale_reset();
+    // Now we should get the proper fresh translation from t().
+    $this->assertTrue($name != $translation_to_en && t($name, array(), array('langcode' => 'en')) == $translation_to_en, t('t() works for English.'));
+    $this->assertTrue(t($name, array(), array('langcode' => LANGUAGE_SYSTEM)) == $name, t('t() works for LANGUAGE_SYSTEM.'));
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    // The indicator should not be here.
+    $this->assertNoRaw($language_indicator, t('String is translated.'));
+
+    // Try to edit a non-existent string and ensure we're redirected correctly.
+    // Assuming we don't have 999,999 strings already.
+    $random_lid = 999999;
+    $this->drupalGet('admin/config/regional/translate/edit/' . $random_lid);
+    $this->assertText(t('String not found'), t('String not found.'));
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/translate', array('absolute' => TRUE)), t('Correct page redirection.'));
+    $this->drupalLogout();
+
+    // Delete the language.
+    $this->drupalLogin($admin_user);
+    $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 %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.
+    $this->assertResponse(404, t('Language no longer found.'));
+    $this->drupalLogout();
+
+    // Delete the string.
+    $this->drupalLogin($translate_user);
+    $search = array(
+      'string' => $name,
+      'language' => 'all',
+      'translation' => 'all',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    // Assume this is the only result, given the random name.
+    $this->clickLink(t('delete'));
+    $this->assertText(t('Are you sure you want to delete the string'), t('"delete" link is correct.'));
+    // Delete the string.
+    $path = 'admin/config/regional/translate/delete/' . $lid;
+    $this->drupalGet($path);
+    // First test the 'cancel' link.
+    $this->clickLink(t('Cancel'));
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/translate', array('absolute' => TRUE)), t('Correct page redirection.'));
+    $this->assertRaw($name, t('The string was not deleted.'));
+    // Delete the name string.
+    $this->drupalPost('admin/config/regional/translate/delete/' . $lid, array(), t('Delete'));
+    $this->assertText(t('The string has been removed.'), t('The string has been removed message.'));
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/translate', array('absolute' => TRUE)), t('Correct page redirection.'));
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    $this->assertNoText($name, t('Search now can not find the name.'));
+  }
+
+  /*
+   * Adds a language and checks that the JavaScript translation files are
+   * properly created and rebuilt on deletion.
+   */
+  function testJavaScriptTranslation() {
+    $user = $this->drupalCreateUser(array('translate interface', 'administer languages', 'access administration pages'));
+    $this->drupalLogin($user);
+
+    $langcode = 'xx';
+    // The English name for the language. This will be translated.
+    $name = $this->randomName(16);
+
+    // Add custom language.
+    $edit = array(
+      'predefined_langcode' => 'custom',
+      'langcode' => $langcode,
+      'name' => $name,
+      'direction' => '0',
+    );
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
+    drupal_static_reset('language_list');
+
+    // Build the JavaScript translation file.
+    $this->drupalGet('admin/config/regional/translate/translate');
+
+    // Retrieve the id of the first string available in the {locales_source}
+    // table and translate it.
+    $query = db_select('locales_source', 'l');
+    $query->addExpression('min(l.lid)', 'lid');
+    $result = $query->condition('l.location', '%.js%', 'LIKE')->execute();
+    $url = 'admin/config/regional/translate/edit/' . $result->fetchObject()->lid;
+    $edit = array('translations['. $langcode .'][0]' => $this->randomName());
+    $this->drupalPost($url, $edit, t('Save translations'));
+
+    // Trigger JavaScript translation parsing and building.
+    _locale_rebuild_js($langcode);
+
+    $locale_javascripts = variable_get('locale_translation_javascript', array());
+    $js_file = 'public://' . variable_get('locale_js_directory', 'languages') . '/' . $langcode . '_' . $locale_javascripts[$langcode] . '.js';
+    $this->assertTrue($result = file_exists($js_file), t('JavaScript file created: %file', array('%file' => $result ? $js_file : t('not found'))));
+
+    // Test JavaScript translation rebuilding.
+    file_unmanaged_delete($js_file);
+    $this->assertTrue($result = !file_exists($js_file), t('JavaScript file deleted: %file', array('%file' => $result ? $js_file : t('found'))));
+    cache_clear_all();
+    _locale_rebuild_js($langcode);
+    $this->assertTrue($result = file_exists($js_file), t('JavaScript file rebuilt: %file', array('%file' => $result ? $js_file : t('not found'))));
+  }
+
+  /**
+   * Tests the validation of the translation input.
+   */
+  function testStringValidation() {
+    global $base_url;
+
+    // User to add language and strings.
+    $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages', 'translate interface'));
+    $this->drupalLogin($admin_user);
+    $langcode = 'xx';
+    // The English name for the language. This will be translated.
+    $name = $this->randomName(16);
+    // This is the language indicator on the translation search screen for
+    // untranslated strings.
+    $language_indicator = "<em class=\"locale-untranslated\">$langcode</em> ";
+    // These will be the invalid translations of $name.
+    $key = $this->randomName(16);
+    $bad_translations[$key] = "<script>alert('xss');</script>" . $key;
+    $key = $this->randomName(16);
+    $bad_translations[$key] = '<img SRC="javascript:alert(\'xss\');">' . $key;
+    $key = $this->randomName(16);
+    $bad_translations[$key] = '<<SCRIPT>alert("xss");//<</SCRIPT>' . $key;
+    $key = $this->randomName(16);
+    $bad_translations[$key] ="<BODY ONLOAD=alert('xss')>" . $key;
+
+    // Add custom language.
+    $edit = array(
+      'predefined_langcode' => 'custom',
+      'langcode' => $langcode,
+      'name' => $name,
+      'direction' => '0',
+    );
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
+    // Add string.
+    t($name, array(), array('langcode' => $langcode));
+    // Reset locale cache.
+    $search = array(
+      'string' => $name,
+      'language' => 'all',
+      'translation' => 'all',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    // Find the edit path.
+    $content = $this->drupalGetContent();
+    $this->assertTrue(preg_match('@(admin/config/regional/translate/edit/[0-9]+)@', $content, $matches), t('Found the edit path.'));
+    $path = $matches[0];
+    foreach ($bad_translations as $key => $translation) {
+      $edit = array(
+        "translations[$langcode][0]" => $translation,
+      );
+      $this->drupalPost($path, $edit, t('Save translations'));
+      // Check for a form error on the textarea.
+      $form_class = $this->xpath('//form[@id="locale-translate-edit-form"]//textarea/@class');
+      $this->assertNotIdentical(FALSE, strpos($form_class[0], 'error'), t('The string was rejected as unsafe.'));
+      $this->assertNoText(t('The string has been saved.'), t('The string was not saved.'));
+    }
+  }
+
+  /**
+   * Tests translation search form.
+   */
+  function testStringSearch() {
+    global $base_url;
+
+    // User to add and remove language.
+    $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
+    // User to translate and delete string.
+    $translate_user = $this->drupalCreateUser(array('translate interface', 'access administration pages'));
+
+    // Code for the language.
+    $langcode = 'xx';
+    // The English name for the language. This will be translated.
+    $name = $this->randomName(16);
+    // This is the language indicator on the translation search screen for
+    // untranslated strings.
+    $language_indicator = "<em class=\"locale-untranslated\">$langcode</em> ";
+    // This will be the translation of $name.
+    $translation = $this->randomName(16);
+
+    // Add custom language.
+    $this->drupalLogin($admin_user);
+    $edit = array(
+      'predefined_langcode' => 'custom',
+      'langcode' => $langcode,
+      'name' => $name,
+      'direction' => '0',
+    );
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
+    // Add string.
+    t($name, array(), array('langcode' => $langcode));
+    // Reset locale cache.
+    locale_reset();
+    $this->drupalLogout();
+
+    // Search for the name.
+    $this->drupalLogin($translate_user);
+    $search = array(
+      'string' => $name,
+      'language' => 'all',
+      'translation' => 'all',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    // assertText() seems to remove the input field where $name always could be
+    // found, so this is not a false assert. See how assertNoText succeeds
+    // later.
+    $this->assertText($name, t('Search found the string.'));
+
+    // Ensure untranslated string doesn't appear if searching on 'only
+    // translated strings'.
+    $search = array(
+      'string' => $name,
+      'language' => 'all',
+      'translation' => 'translated',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    $this->assertText(t('No strings available.'), t("Search didn't find the string."));
+
+    // Ensure untranslated string appears if searching on 'only untranslated
+    // strings'.
+    $search = array(
+      'string' => $name,
+      'language' => 'all',
+      'translation' => 'untranslated',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    $this->assertNoText(t('No strings available.'), t('Search found the string.'));
+
+    // Add translation.
+    // Assume this is the only result, given the random name.
+    $this->clickLink(t('edit'));
+    // We save the lid from the path.
+    $matches = array();
+    preg_match('!admin/config/regional/translate/edit/(\d)+!', $this->getUrl(), $matches);
+    $lid = $matches[1];
+    $edit = array(
+      "translations[$langcode][0]" => $translation,
+    );
+    $this->drupalPost(NULL, $edit, t('Save translations'));
+
+    // Ensure translated string does appear if searching on 'only
+    // translated strings'.
+    $search = array(
+      'string' => $translation,
+      'language' => 'all',
+      'translation' => 'translated',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    $this->assertNoText(t('No strings available.'), t('Search found the translation.'));
+
+    // Ensure translated source string doesn't appear if searching on 'only
+    // untranslated strings'.
+    $search = array(
+      'string' => $name,
+      'language' => 'all',
+      'translation' => 'untranslated',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    $this->assertText(t('No strings available.'), t("Search didn't find the source string."));
+
+    // Ensure translated string doesn't appear if searching on 'only
+    // untranslated strings'.
+    $search = array(
+      'string' => $translation,
+      'language' => 'all',
+      'translation' => 'untranslated',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    $this->assertText(t('No strings available.'), t("Search didn't find the translation."));
+
+    // Ensure translated string does appear if searching on the custom language.
+    $search = array(
+      'string' => $translation,
+      'language' => $langcode,
+      'translation' => 'all',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    $this->assertNoText(t('No strings available.'), t('Search found the translation.'));
+
+    // Ensure translated string doesn't appear if searching in System (English).
+    $search = array(
+      'string' => $translation,
+      'language' => LANGUAGE_SYSTEM,
+      'translation' => 'all',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    $this->assertText(t('No strings available.'), t("Search didn't find the translation."));
+
+    // Search for a string that isn't in the system.
+    $unavailable_string = $this->randomName(16);
+    $search = array(
+      'string' => $unavailable_string,
+      'language' => 'all',
+      'translation' => 'all',
+    );
+    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+    $this->assertText(t('No strings available.'), t("Search didn't find the invalid string."));
+  }
+}
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallFrenchTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallFrenchTest.php
new file mode 100644
index 0000000..047ff63
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallFrenchTest.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\locale\Tests\LocaleUninstallFrenchTest.
+ */
+
+namespace Drupal\locale\Tests;
+
+/**
+ * Locale uninstall with French UI functional test.
+ *
+ * Because this class extends LocaleUninstallFunctionalTest, it doesn't require a new
+ * test of its own. Rather, it switches the default UI language in setUp and then
+ * runs the testUninstallProcess (which it inherits from LocaleUninstallFunctionalTest)
+ * to test with this new language.
+ */
+class LocaleUninstallFrenchTest extends LocaleUninstallTest {
+  public static function getInfo() {
+    return array(
+      'name' => 'Locale uninstall (FR)',
+      'description' => 'Tests the uninstall process using French as interface language.',
+      'group' => 'Locale',
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+    $this->langcode = 'fr';
+  }
+}
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
new file mode 100644
index 0000000..72868e9
--- /dev/null
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
@@ -0,0 +1,132 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\locale\Tests\LocaleUninstallTest.
+ */
+
+namespace Drupal\locale\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Locale uninstall with English UI functional test.
+ */
+class LocaleUninstallTest extends WebTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Locale uninstall (EN)',
+      'description' => 'Tests the uninstall process using the built-in UI language.',
+      'group' => 'Locale',
+    );
+  }
+
+  /**
+   * The default language set for the UI before uninstall.
+   */
+  protected $language;
+
+  function setUp() {
+    parent::setUp(array('node', 'locale'));
+    $this->langcode = 'en';
+
+    // Create Article node type.
+    $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
+  }
+
+  /**
+   * Check if the values of the Locale variables are correct after uninstall.
+   */
+  function testUninstallProcess() {
+    $locale_module = array('locale', 'language');
+
+    $language = (object) array(
+      'langcode' => 'fr',
+      'name' => 'French',
+      'default' => $this->langcode == 'fr',
+    );
+    language_save($language);
+
+    // Check the UI language.
+    drupal_language_initialize();
+    $this->assertEqual(drupal_container()->get(LANGUAGE_TYPE_INTERFACE)->langcode, $this->langcode, t('Current language: %lang', array('%lang' => drupal_container()->get(LANGUAGE_TYPE_INTERFACE)->langcode)));
+
+    // Enable multilingual workflow option for articles.
+    variable_set('node_type_language_article', 1);
+
+    // Change JavaScript translations directory.
+    variable_set('locale_js_directory', 'js_translations');
+
+    // Build the JavaScript translation file for French.
+    $user = $this->drupalCreateUser(array('translate interface', 'access administration pages'));
+    $this->drupalLogin($user);
+    $this->drupalGet('admin/config/regional/translate/translate');
+    $string = db_query('SELECT min(lid) AS lid FROM {locales_source} WHERE location LIKE :location', array(
+      ':location' => '%.js%',
+    ))->fetchObject();
+    $edit = array('translations[fr][0]' => 'french translation');
+    $this->drupalPost('admin/config/regional/translate/edit/' . $string->lid, $edit, t('Save translations'));
+    _locale_rebuild_js('fr');
+    $locale_javascripts = variable_get('locale_translation_javascript', array());
+    $js_file = 'public://' . variable_get('locale_js_directory', 'languages') . '/fr_' . $locale_javascripts['fr'] . '.js';
+    $this->assertTrue($result = file_exists($js_file), t('JavaScript file created: %file', array('%file' => $result ? $js_file : t('none'))));
+
+    // Disable string caching.
+    variable_set('locale_cache_strings', 0);
+
+    // Change language negotiation options.
+    drupal_load('module', 'locale');
+    variable_set('language_types', language_types_get_default() + array('language_custom' => TRUE));
+    variable_set('language_negotiation_' . LANGUAGE_TYPE_INTERFACE, language_language_negotiation_info());
+    variable_set('language_negotiation_' . LANGUAGE_TYPE_CONTENT, language_language_negotiation_info());
+    variable_set('language_negotiation_' . LANGUAGE_TYPE_URL, language_language_negotiation_info());
+
+    // Change language negotiation settings.
+    variable_set('language_negotiation_url_part', LANGUAGE_NEGOTIATION_URL_PREFIX);
+    variable_set('language_negotiation_session_param', TRUE);
+
+    // Uninstall Locale.
+    module_disable($locale_module);
+    drupal_uninstall_modules($locale_module);
+
+    // Visit the front page.
+    $this->drupalGet('');
+
+    // Check the init language logic.
+    drupal_language_initialize();
+    $this->assertEqual(drupal_container()->get(LANGUAGE_TYPE_INTERFACE)->langcode, 'en', t('Language after uninstall: %lang', array('%lang' => drupal_container()->get(LANGUAGE_TYPE_INTERFACE)->langcode)));
+
+    // Check JavaScript files deletion.
+    $this->assertTrue($result = !file_exists($js_file), t('JavaScript file deleted: %file', array('%file' => $result ? $js_file : t('found'))));
+
+    // Check language count.
+    $language_count = variable_get('language_count', 1);
+    $this->assertEqual($language_count, 1, t('Language count: %count', array('%count' => $language_count)));
+
+    // Check language negotiation.
+    require_once DRUPAL_ROOT . '/core/includes/language.inc';
+    $this->assertTrue(count(language_types_get_all()) == count(language_types_get_default()), t('Language types reset'));
+    $language_negotiation = language_negotiation_method_get_first(LANGUAGE_TYPE_INTERFACE) == LANGUAGE_NEGOTIATION_DEFAULT;
+    $this->assertTrue($language_negotiation, t('Interface language negotiation: %setting', array('%setting' => t($language_negotiation ? 'none' : 'set'))));
+    $language_negotiation = language_negotiation_method_get_first(LANGUAGE_TYPE_CONTENT) == LANGUAGE_NEGOTIATION_DEFAULT;
+    $this->assertTrue($language_negotiation, t('Content language negotiation: %setting', array('%setting' => t($language_negotiation ? 'none' : 'set'))));
+    $language_negotiation = language_negotiation_method_get_first(LANGUAGE_TYPE_URL) == LANGUAGE_NEGOTIATION_DEFAULT;
+    $this->assertTrue($language_negotiation, t('URL language negotiation: %setting', array('%setting' => t($language_negotiation ? 'none' : 'set'))));
+
+    // Check language negotiation method settings.
+    $this->assertFalse(variable_get('language_negotiation_url_part', FALSE), t('URL language negotiation method indicator settings cleared.'));
+    $this->assertFalse(variable_get('language_negotiation_session_param', FALSE), t('Visit language negotiation method settings cleared.'));
+
+    // Check JavaScript parsed.
+    $javascript_parsed_count = count(variable_get('javascript_parsed', array()));
+    $this->assertEqual($javascript_parsed_count, 0, t('JavaScript parsed count: %count', array('%count' => $javascript_parsed_count)));
+
+    // Check JavaScript translations directory.
+    $locale_js_directory = variable_get('locale_js_directory', 'languages');
+    $this->assertEqual($locale_js_directory, 'languages', t('JavaScript translations directory: %dir', array('%dir' => $locale_js_directory)));
+
+    // Check string caching.
+    $locale_cache_strings = variable_get('locale_cache_strings', 1);
+    $this->assertEqual($locale_cache_strings, 1, t('String caching: %status', array('%status' => t($locale_cache_strings ? 'enabled': 'disabled'))));
+  }
+}
diff --git a/core/modules/locale/locale.info b/core/modules/locale/locale.info
index 8b3e5f7..e0749db 100644
--- a/core/modules/locale/locale.info
+++ b/core/modules/locale/locale.info
@@ -4,4 +4,3 @@ package = Core
 version = VERSION
 core = 8.x
 dependencies[] = language
-files[] = locale.test
diff --git a/core/modules/locale/locale.test b/core/modules/locale/locale.test
deleted file mode 100644
index 5e252bf..0000000
--- a/core/modules/locale/locale.test
+++ /dev/null
@@ -1,2263 +0,0 @@
-<?php
-
-/**
- * @file
- * Tests for locale.module.
- *
- * The test file includes:
- *  - a functional test for the language configuration forms;
- *  - functional tests for the translation functionalities, including searching;
- *  - a functional test for the PO files import feature, including validation;
- *  - functional tests for translations and templates export feature;
- *  - functional tests for the uninstall process;
- *  - a functional test for the language switching feature;
- *  - a functional test for a user's ability to change their default language;
- *  - a functional test for configuring a different path alias per language;
- *  - a functional test for configuring a different path alias per language;
- *  - a functional test for multilingual support by content type and on nodes.
- *  - a functional test for multilingual fields.
- *  - a functional test for comment language.
- *  - a functional test fot language types/negotiation info.
- */
-
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Functional tests for JavaScript parsing for translatable strings.
- */
-class LocaleJavascriptTranslationTest extends WebTestBase {
-  public static function getInfo() {
-    return array(
-      'name' => 'Javascript translation',
-      'description' => 'Tests parsing js files for translatable strings',
-      'group' => 'Locale',
-    );
-  }
-
-  function setUp() {
-    parent::setUp('locale');
-  }
-
-  function testFileParsing() {
-
-    $filename = drupal_get_path('module', 'locale') . '/tests/locale_test.js';
-
-    // Parse the file to look for source strings.
-    _locale_parse_js_file($filename);
-
-    // Get all of the source strings that were found.
-    $source_strings = db_select('locales_source', 's')
-      ->fields('s', array('source', 'context'))
-      ->condition('s.location', $filename)
-      ->execute()
-      ->fetchAllKeyed();
-
-    // List of all strings that should be in the file.
-    $test_strings = array(
-      "Standard Call t" => '',
-      "Whitespace Call t" => '',
-
-      "Single Quote t" => '',
-      "Single Quote \\'Escaped\\' t" => '',
-      "Single Quote Concat strings t" => '',
-
-      "Double Quote t" => '',
-      "Double Quote \\\"Escaped\\\" t" => '',
-      "Double Quote Concat strings t" => '',
-
-      "Context !key Args t" => "Context string",
-
-      "Context Unquoted t" => "Context string unquoted",
-      "Context Single Quoted t" => "Context string single quoted",
-      "Context Double Quoted t" => "Context string double quoted",
-
-      "Standard Call plural" => '',
-      "Standard Call @count plural" => '',
-      "Whitespace Call plural" => '',
-      "Whitespace Call @count plural" => '',
-
-      "Single Quote plural" => '',
-      "Single Quote @count plural" => '',
-      "Single Quote \\'Escaped\\' plural" => '',
-      "Single Quote \\'Escaped\\' @count plural" => '',
-
-      "Double Quote plural" => '',
-      "Double Quote @count plural" => '',
-      "Double Quote \\\"Escaped\\\" plural" => '',
-      "Double Quote \\\"Escaped\\\" @count plural" => '',
-
-      "Context !key Args plural" => "Context string",
-      "Context !key Args @count plural" => "Context string",
-
-      "Context Unquoted plural" => "Context string unquoted",
-      "Context Unquoted @count plural" => "Context string unquoted",
-      "Context Single Quoted plural" => "Context string single quoted",
-      "Context Single Quoted @count plural" => "Context string single quoted",
-      "Context Double Quoted plural" => "Context string double quoted",
-      "Context Double Quoted @count plural" => "Context string double quoted",
-    );
-
-    // Assert that all strings were found properly.
-    foreach ($test_strings as $str => $context) {
-      $args = array('%source' => $str, '%context' => $context);
-
-      // Make sure that the string was found in the file.
-      $this->assertTrue(isset($source_strings[$str]), t("Found source string: %source", $args));
-
-      // Make sure that the proper context was matched.
-      $this->assertTrue(isset($source_strings[$str]) && $source_strings[$str] === $context, strlen($context) > 0 ? t("Context for %source is %context", $args) : t("Context for %source is blank", $args));
-    }
-
-    $this->assertEqual(count($source_strings), count($test_strings), t("Found correct number of source strings."));
-  }
-}
-
-/**
- * Functional test for string translation and validation.
- */
-class LocaleTranslationFunctionalTest extends WebTestBase {
-  public static function getInfo() {
-    return array(
-      'name' => 'String translate, search and validate',
-      'description' => 'Adds a new locale and translates its name. Checks the validation of translation strings and search results.',
-      'group' => 'Locale',
-    );
-  }
-
-  function setUp() {
-    parent::setUp('locale');
-  }
-
-  /**
-   * Adds a language and tests string translation by users with the appropriate permissions.
-   */
-  function testStringTranslation() {
-    global $base_url;
-
-    // User to add and remove language.
-    $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
-    // User to translate and delete string.
-    $translate_user = $this->drupalCreateUser(array('translate interface', 'access administration pages'));
-    // Code for the language.
-    $langcode = 'xx';
-    // The English name for the language. This will be translated.
-    $name = $this->randomName(16);
-    // This is the language indicator on the translation search screen for
-    // untranslated strings.
-    $language_indicator = "<em class=\"locale-untranslated\">$langcode</em> ";
-    // This will be the translation of $name.
-    $translation = $this->randomName(16);
-    $translation_to_en = $this->randomName(16);
-
-    // Add custom language.
-    $this->drupalLogin($admin_user);
-    $edit = array(
-      'predefined_langcode' => 'custom',
-      'langcode' => $langcode,
-      'name' => $name,
-      'direction' => '0',
-    );
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
-    // Add string.
-    t($name, array(), array('langcode' => $langcode));
-    // Reset locale cache.
-    locale_reset();
-    $this->assertRaw('"edit-site-default-' . $langcode .'"', t('Language code found.'));
-    $this->assertText(t($name), t('Test language added.'));
-    $this->drupalLogout();
-
-    // Search for the name and translate it.
-    $this->drupalLogin($translate_user);
-    $search = array(
-      'string' => $name,
-      'language' => 'all',
-      'translation' => 'all',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    // assertText() seems to remove the input field where $name always could be
-    // found, so this is not a false assert. See how assertNoText succeeds
-    // later.
-    $this->assertText($name, t('Search found the name.'));
-    $this->assertRaw($language_indicator, t('Name is untranslated.'));
-    // Assume this is the only result, given the random name.
-    $this->clickLink(t('edit'));
-    // We save the lid from the path.
-    $matches = array();
-    preg_match('!admin/config/regional/translate/edit/(\d+)!', $this->getUrl(), $matches);
-    $lid = $matches[1];
-    // No t() here, it's surely not translated yet.
-    $this->assertText($name, t('name found on edit screen.'));
-    $this->assertNoText('English', t('No way to translate the string to English.'));
-    $this->drupalLogout();
-    $this->drupalLogin($admin_user);
-    $this->drupalPost('admin/config/regional/language/edit/en', array('locale_translate_english' => TRUE), t('Save language'));
-    $this->drupalLogout();
-    $this->drupalLogin($translate_user);
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    // assertText() seems to remove the input field where $name always could be
-    // found, so this is not a false assert. See how assertNoText succeeds
-    // later.
-    $this->assertText($name, t('Search found the name.'));
-    $this->assertRaw($language_indicator, t('Name is untranslated.'));
-    // Assume this is the only result, given the random name.
-    $this->clickLink(t('edit'));
-    $string_edit_url = $this->getUrl();
-    $edit = array(
-      "translations[$langcode][0]" => $translation,
-      'translations[en][0]' => $translation_to_en,
-    );
-    $this->drupalPost(NULL, $edit, t('Save translations'));
-    $this->assertText(t('The string has been saved.'), t('The string has been saved.'));
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/translate', array('absolute' => TRUE)), t('Correct page redirection.'));
-    $this->drupalGet($string_edit_url);
-    $this->assertRaw($translation, t('Non-English translation properly saved.'));
-    $this->assertRaw($translation_to_en, t('English translation properly saved.'));
-    $this->assertTrue($name != $translation && t($name, array(), array('langcode' => $langcode)) == $translation, t('t() works for non-English.'));
-    // Refresh the locale() cache to get fresh data from t() below. We are in
-    // the same HTTP request and therefore t() is not refreshed by saving the
-    // translation above.
-    locale_reset();
-    // Now we should get the proper fresh translation from t().
-    $this->assertTrue($name != $translation_to_en && t($name, array(), array('langcode' => 'en')) == $translation_to_en, t('t() works for English.'));
-    $this->assertTrue(t($name, array(), array('langcode' => LANGUAGE_SYSTEM)) == $name, t('t() works for LANGUAGE_SYSTEM.'));
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    // The indicator should not be here.
-    $this->assertNoRaw($language_indicator, t('String is translated.'));
-
-    // Try to edit a non-existent string and ensure we're redirected correctly.
-    // Assuming we don't have 999,999 strings already.
-    $random_lid = 999999;
-    $this->drupalGet('admin/config/regional/translate/edit/' . $random_lid);
-    $this->assertText(t('String not found'), t('String not found.'));
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/translate', array('absolute' => TRUE)), t('Correct page redirection.'));
-    $this->drupalLogout();
-
-    // Delete the language.
-    $this->drupalLogin($admin_user);
-    $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 %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.
-    $this->assertResponse(404, t('Language no longer found.'));
-    $this->drupalLogout();
-
-    // Delete the string.
-    $this->drupalLogin($translate_user);
-    $search = array(
-      'string' => $name,
-      'language' => 'all',
-      'translation' => 'all',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    // Assume this is the only result, given the random name.
-    $this->clickLink(t('delete'));
-    $this->assertText(t('Are you sure you want to delete the string'), t('"delete" link is correct.'));
-    // Delete the string.
-    $path = 'admin/config/regional/translate/delete/' . $lid;
-    $this->drupalGet($path);
-    // First test the 'cancel' link.
-    $this->clickLink(t('Cancel'));
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/translate', array('absolute' => TRUE)), t('Correct page redirection.'));
-    $this->assertRaw($name, t('The string was not deleted.'));
-    // Delete the name string.
-    $this->drupalPost('admin/config/regional/translate/delete/' . $lid, array(), t('Delete'));
-    $this->assertText(t('The string has been removed.'), t('The string has been removed message.'));
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/translate', array('absolute' => TRUE)), t('Correct page redirection.'));
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    $this->assertNoText($name, t('Search now can not find the name.'));
-  }
-
-  /*
-   * Adds a language and checks that the JavaScript translation files are
-   * properly created and rebuilt on deletion.
-   */
-  function testJavaScriptTranslation() {
-    $user = $this->drupalCreateUser(array('translate interface', 'administer languages', 'access administration pages'));
-    $this->drupalLogin($user);
-
-    $langcode = 'xx';
-    // The English name for the language. This will be translated.
-    $name = $this->randomName(16);
-
-    // Add custom language.
-    $edit = array(
-      'predefined_langcode' => 'custom',
-      'langcode' => $langcode,
-      'name' => $name,
-      'direction' => '0',
-    );
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
-    drupal_static_reset('language_list');
-
-    // Build the JavaScript translation file.
-    $this->drupalGet('admin/config/regional/translate/translate');
-
-    // Retrieve the id of the first string available in the {locales_source}
-    // table and translate it.
-    $query = db_select('locales_source', 'l');
-    $query->addExpression('min(l.lid)', 'lid');
-    $result = $query->condition('l.location', '%.js%', 'LIKE')->execute();
-    $url = 'admin/config/regional/translate/edit/' . $result->fetchObject()->lid;
-    $edit = array('translations['. $langcode .'][0]' => $this->randomName());
-    $this->drupalPost($url, $edit, t('Save translations'));
-
-    // Trigger JavaScript translation parsing and building.
-    _locale_rebuild_js($langcode);
-
-    $locale_javascripts = variable_get('locale_translation_javascript', array());
-    $js_file = 'public://' . variable_get('locale_js_directory', 'languages') . '/' . $langcode . '_' . $locale_javascripts[$langcode] . '.js';
-    $this->assertTrue($result = file_exists($js_file), t('JavaScript file created: %file', array('%file' => $result ? $js_file : t('not found'))));
-
-    // Test JavaScript translation rebuilding.
-    file_unmanaged_delete($js_file);
-    $this->assertTrue($result = !file_exists($js_file), t('JavaScript file deleted: %file', array('%file' => $result ? $js_file : t('found'))));
-    cache_clear_all();
-    _locale_rebuild_js($langcode);
-    $this->assertTrue($result = file_exists($js_file), t('JavaScript file rebuilt: %file', array('%file' => $result ? $js_file : t('not found'))));
-  }
-
-  /**
-   * Tests the validation of the translation input.
-   */
-  function testStringValidation() {
-    global $base_url;
-
-    // User to add language and strings.
-    $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages', 'translate interface'));
-    $this->drupalLogin($admin_user);
-    $langcode = 'xx';
-    // The English name for the language. This will be translated.
-    $name = $this->randomName(16);
-    // This is the language indicator on the translation search screen for
-    // untranslated strings.
-    $language_indicator = "<em class=\"locale-untranslated\">$langcode</em> ";
-    // These will be the invalid translations of $name.
-    $key = $this->randomName(16);
-    $bad_translations[$key] = "<script>alert('xss');</script>" . $key;
-    $key = $this->randomName(16);
-    $bad_translations[$key] = '<img SRC="javascript:alert(\'xss\');">' . $key;
-    $key = $this->randomName(16);
-    $bad_translations[$key] = '<<SCRIPT>alert("xss");//<</SCRIPT>' . $key;
-    $key = $this->randomName(16);
-    $bad_translations[$key] ="<BODY ONLOAD=alert('xss')>" . $key;
-
-    // Add custom language.
-    $edit = array(
-      'predefined_langcode' => 'custom',
-      'langcode' => $langcode,
-      'name' => $name,
-      'direction' => '0',
-    );
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
-    // Add string.
-    t($name, array(), array('langcode' => $langcode));
-    // Reset locale cache.
-    $search = array(
-      'string' => $name,
-      'language' => 'all',
-      'translation' => 'all',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    // Find the edit path.
-    $content = $this->drupalGetContent();
-    $this->assertTrue(preg_match('@(admin/config/regional/translate/edit/[0-9]+)@', $content, $matches), t('Found the edit path.'));
-    $path = $matches[0];
-    foreach ($bad_translations as $key => $translation) {
-      $edit = array(
-        "translations[$langcode][0]" => $translation,
-      );
-      $this->drupalPost($path, $edit, t('Save translations'));
-      // Check for a form error on the textarea.
-      $form_class = $this->xpath('//form[@id="locale-translate-edit-form"]//textarea/@class');
-      $this->assertNotIdentical(FALSE, strpos($form_class[0], 'error'), t('The string was rejected as unsafe.'));
-      $this->assertNoText(t('The string has been saved.'), t('The string was not saved.'));
-    }
-  }
-
-  /**
-   * Tests translation search form.
-   */
-  function testStringSearch() {
-    global $base_url;
-
-    // User to add and remove language.
-    $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
-    // User to translate and delete string.
-    $translate_user = $this->drupalCreateUser(array('translate interface', 'access administration pages'));
-
-    // Code for the language.
-    $langcode = 'xx';
-    // The English name for the language. This will be translated.
-    $name = $this->randomName(16);
-    // This is the language indicator on the translation search screen for
-    // untranslated strings.
-    $language_indicator = "<em class=\"locale-untranslated\">$langcode</em> ";
-    // This will be the translation of $name.
-    $translation = $this->randomName(16);
-
-    // Add custom language.
-    $this->drupalLogin($admin_user);
-    $edit = array(
-      'predefined_langcode' => 'custom',
-      'langcode' => $langcode,
-      'name' => $name,
-      'direction' => '0',
-    );
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
-    // Add string.
-    t($name, array(), array('langcode' => $langcode));
-    // Reset locale cache.
-    locale_reset();
-    $this->drupalLogout();
-
-    // Search for the name.
-    $this->drupalLogin($translate_user);
-    $search = array(
-      'string' => $name,
-      'language' => 'all',
-      'translation' => 'all',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    // assertText() seems to remove the input field where $name always could be
-    // found, so this is not a false assert. See how assertNoText succeeds
-    // later.
-    $this->assertText($name, t('Search found the string.'));
-
-    // Ensure untranslated string doesn't appear if searching on 'only
-    // translated strings'.
-    $search = array(
-      'string' => $name,
-      'language' => 'all',
-      'translation' => 'translated',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    $this->assertText(t('No strings available.'), t("Search didn't find the string."));
-
-    // Ensure untranslated string appears if searching on 'only untranslated
-    // strings'.
-    $search = array(
-      'string' => $name,
-      'language' => 'all',
-      'translation' => 'untranslated',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    $this->assertNoText(t('No strings available.'), t('Search found the string.'));
-
-    // Add translation.
-    // Assume this is the only result, given the random name.
-    $this->clickLink(t('edit'));
-    // We save the lid from the path.
-    $matches = array();
-    preg_match('!admin/config/regional/translate/edit/(\d)+!', $this->getUrl(), $matches);
-    $lid = $matches[1];
-    $edit = array(
-      "translations[$langcode][0]" => $translation,
-    );
-    $this->drupalPost(NULL, $edit, t('Save translations'));
-
-    // Ensure translated string does appear if searching on 'only
-    // translated strings'.
-    $search = array(
-      'string' => $translation,
-      'language' => 'all',
-      'translation' => 'translated',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    $this->assertNoText(t('No strings available.'), t('Search found the translation.'));
-
-    // Ensure translated source string doesn't appear if searching on 'only
-    // untranslated strings'.
-    $search = array(
-      'string' => $name,
-      'language' => 'all',
-      'translation' => 'untranslated',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    $this->assertText(t('No strings available.'), t("Search didn't find the source string."));
-
-    // Ensure translated string doesn't appear if searching on 'only
-    // untranslated strings'.
-    $search = array(
-      'string' => $translation,
-      'language' => 'all',
-      'translation' => 'untranslated',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    $this->assertText(t('No strings available.'), t("Search didn't find the translation."));
-
-    // Ensure translated string does appear if searching on the custom language.
-    $search = array(
-      'string' => $translation,
-      'language' => $langcode,
-      'translation' => 'all',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    $this->assertNoText(t('No strings available.'), t('Search found the translation.'));
-
-    // Ensure translated string doesn't appear if searching in System (English).
-    $search = array(
-      'string' => $translation,
-      'language' => LANGUAGE_SYSTEM,
-      'translation' => 'all',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    $this->assertText(t('No strings available.'), t("Search didn't find the translation."));
-
-    // Search for a string that isn't in the system.
-    $unavailable_string = $this->randomName(16);
-    $search = array(
-      'string' => $unavailable_string,
-      'language' => 'all',
-      'translation' => 'all',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    $this->assertText(t('No strings available.'), t("Search didn't find the invalid string."));
-  }
-}
-
-/**
- * Tests plural format handling functionality.
- */
-class LocalePluralFormatTest extends WebTestBase {
-  public static function getInfo() {
-    return array(
-      'name' => 'Plural handling',
-      'description' => 'Tests plural handling for various languages.',
-      'group' => 'Locale',
-    );
-  }
-
-  function setUp() {
-    parent::setUp('locale');
-
-    $admin_user = $this->drupalCreateUser(array('administer languages', 'translate interface', 'access administration pages'));
-    $this->drupalLogin($admin_user);
-  }
-
-  /**
-   * Tests locale_get_plural() and format_plural() functionality.
-   */
-  function testGetPluralFormat() {
-    // Import some .po files with formulas to set up the environment.
-    // These will also add the languages to the system and enable them.
-    $this->importPoFile($this->getPoFileWithSimplePlural(), array(
-      'langcode' => 'fr',
-    ));
-    $this->importPoFile($this->getPoFileWithComplexPlural(), array(
-      'langcode' => 'hr',
-    ));
-
-    // Attempt to import some broken .po files as well to prove that these
-    // will not overwrite the proper plural formula imported above.
-    $this->importPoFile($this->getPoFileWithMissingPlural(), array(
-      'langcode' => 'fr',
-      'overwrite_options[not_customized]' => TRUE,
-    ));
-    $this->importPoFile($this->getPoFileWithBrokenPlural(), array(
-      'langcode' => 'hr',
-      'overwrite_options[not_customized]' => TRUE,
-    ));
-
-    // Reset static caches from locale_get_plural() to ensure we get fresh data.
-    drupal_static_reset('locale_get_plural');
-    drupal_static_reset('locale_get_plural:plurals');
-    drupal_static_reset('locale');
-
-    // Expected plural translation strings for each plural index.
-    $plural_strings = array(
-      // English is not imported in this case, so we assume built-in text
-      // and formulas.
-      'en' => array(
-        0 => '1 hour',
-        1 => '@count hours',
-      ),
-      'fr' => array(
-        0 => '1 heure',
-        1 => '@count heures',
-      ),
-      'hr' => array(
-        0 => '@count sat',
-        1 => '@count sata',
-        2 => '@count sati',
-      ),
-      // Hungarian is not imported, so it should assume the same text as
-      // English, but it will always pick the plural form as per the built-in
-      // logic, so only index -1 is relevant with the plural value.
-      'hu' => array(
-        0 => '1 hour',
-        -1 => '@count hours',
-      ),
-    );
-
-    // Expected plural indexes precomputed base on the plural formulas with
-    // given $count value.
-    $plural_tests = array(
-      'en' => array(
-        1 => 0,
-        0 => 1,
-        5 => 1,
-      ),
-      'fr' => array(
-        1 => 0,
-        0 => 0,
-        5 => 1,
-      ),
-      'hr' => array(
-        1 => 0,
-        21 => 0,
-        0 => 2,
-        2 => 1,
-        8 => 2,
-      ),
-      'hu' => array(
-        1 => -1,
-        21 => -1,
-        0 => -1,
-      ),
-    );
-
-    foreach ($plural_tests as $langcode => $tests) {
-      foreach ($tests as $count => $expected_plural_index) {
-        // Assert that the we get the right plural index.
-        $this->assertIdentical(locale_get_plural($count, $langcode), $expected_plural_index, 'Computed plural index for ' . $langcode . ' for count ' . $count . ' is ' . $expected_plural_index);
-        // Assert that the we get the right translation for that. Change the
-        // expected index as per the logic for translation lookups.
-        $expected_plural_index = ($count == 1) ? 0 : $expected_plural_index;
-        $expected_plural_string = str_replace('@count', $count, $plural_strings[$langcode][$expected_plural_index]);
-        $this->assertIdentical(format_plural($count, '1 hour', '@count hours', array(), array('langcode' => $langcode)), $expected_plural_string, 'Plural translation of 1 hours / @count hours for count ' . $count . ' in ' . $langcode . ' is ' . $expected_plural_string);
-      }
-    }
-  }
-
-  /**
-   * Tests plural editing and export functionality.
-   */
-  function testPluralEditExport() {
-    // Import some .po files with formulas to set up the environment.
-    // These will also add the languages to the system and enable them.
-    $this->importPoFile($this->getPoFileWithSimplePlural(), array(
-      'langcode' => 'fr',
-    ));
-    $this->importPoFile($this->getPoFileWithComplexPlural(), array(
-      'langcode' => 'hr',
-    ));
-
-    // Get the French translations.
-    $this->drupalPost('admin/config/regional/translate/export', array(
-      'langcode' => 'fr',
-    ), t('Export'));
-    // Ensure we have a translation file.
-    $this->assertRaw('# French translation of Drupal', t('Exported French translation file.'));
-    // Ensure our imported translations exist in the file.
-    $this->assertRaw("msgid \"Monday\"\nmsgstr \"lundi\"", t('French translations present in exported file.'));
-    // Check for plural export specifically.
-    $this->assertRaw("msgid \"1 hour\"\nmsgid_plural \"@count hours\"\nmsgstr[0] \"1 heure\"\nmsgstr[1] \"@count heures\"", t('Plural translations exported properly.'));
-
-    // Get the Croatian translations.
-    $this->drupalPost('admin/config/regional/translate/export', array(
-      'langcode' => 'hr',
-    ), t('Export'));
-    // Ensure we have a translation file.
-    $this->assertRaw('# Croatian translation of Drupal', t('Exported Croatian translation file.'));
-    // Ensure our imported translations exist in the file.
-    $this->assertRaw("msgid \"Monday\"\nmsgstr \"Ponedjeljak\"", t('Croatian translations present in exported file.'));
-    // Check for plural export specifically.
-    $this->assertRaw("msgid \"1 hour\"\nmsgid_plural \"@count hours\"\nmsgstr[0] \"@count sat\"\nmsgstr[1] \"@count sata\"\nmsgstr[2] \"@count sati\"", t('Plural translations exported properly.'));
-
-    // Check if the source appears on the translation page.
-    $this->drupalGet('admin/config/regional/translate');
-    $this->assertText("1 hour, @count hours");
-
-    // Look up editing page for this plural string and check fields.
-    $lid = db_query("SELECT lid FROM {locales_source} WHERE source = :source AND context = ''", array(':source' => "1 hour" . LOCALE_PLURAL_DELIMITER . "@count hours"))->fetchField();
-    $path = 'admin/config/regional/translate/edit/' . $lid;
-    $this->drupalGet($path);
-    // Labels for plural editing elements.
-    $this->assertText('Singular form');
-    $this->assertText('First plural form');
-    $this->assertText('2. plural form');
-    // Plural values for both languages.
-    $this->assertFieldById('edit-translations-hr-0', '@count sat');
-    $this->assertFieldById('edit-translations-hr-1', '@count sata');
-    $this->assertFieldById('edit-translations-hr-2', '@count sati');
-    $this->assertNoFieldById('edit-translations-hr-3');
-    $this->assertFieldById('edit-translations-fr-0', '1 heure');
-    $this->assertFieldById('edit-translations-fr-1', '@count heures');
-    $this->assertNoFieldById('edit-translations-fr-2');
-
-    // Edit some translations and see if that took effect.
-    $edit = array(
-      'translations[fr][0]' => '1 heure edited',
-      'translations[hr][1]' => '@count sata edited',
-    );
-    $this->drupalPost($path, $edit, t('Save translations'));
-
-    // Inject a plural source string to the database. We need to use a specific
-    // langcode here because the language will be English by default and will
-    // not save our source string for performance optimization if we do not ask
-    // specifically for a language.
-    format_plural(1, '1 day', '@count days', array(), array('langcode' => 'fr'));
-    // Look up editing page for this plural string and check fields.
-    $lid = db_query("SELECT lid FROM {locales_source} WHERE source = :source AND context = ''", array(':source' => "1 day" . LOCALE_PLURAL_DELIMITER . "@count days"))->fetchField();
-    $path = 'admin/config/regional/translate/edit/' . $lid;
-
-    // Save complete translations for the string in both languages.
-    $edit = array(
-      'translations[fr][0]' => '1 jour',
-      'translations[fr][1]' => '@count jours',
-      'translations[hr][0]' => '@count dan',
-      'translations[hr][1]' => '@count dana',
-      'translations[hr][2]' => '@count dana',
-    );
-    $this->drupalPost($path, $edit, t('Save translations'));
-
-    // Get the French translations.
-    $this->drupalPost('admin/config/regional/translate/export', array(
-      'langcode' => 'fr',
-    ), t('Export'));
-    // Check for plural export specifically.
-    $this->assertRaw("msgid \"1 hour\"\nmsgid_plural \"@count hours\"\nmsgstr[0] \"1 heure edited\"\nmsgstr[1] \"@count heures\"", t('Edited French plural translations for hours exported properly.'));
-    $this->assertRaw("msgid \"1 day\"\nmsgid_plural \"@count days\"\nmsgstr[0] \"1 jour\"\nmsgstr[1] \"@count jours\"", t('Added French plural translations for days exported properly.'));
-
-    // Get the Croatian translations.
-    $this->drupalPost('admin/config/regional/translate/export', array(
-      'langcode' => 'hr',
-    ), t('Export'));
-    // Check for plural export specifically.
-    $this->assertRaw("msgid \"1 hour\"\nmsgid_plural \"@count hours\"\nmsgstr[0] \"@count sat\"\nmsgstr[1] \"@count sata edited\"\nmsgstr[2] \"@count sati\"", t('Edited Croatian plural translations exported properly.'));
-    $this->assertRaw("msgid \"1 day\"\nmsgid_plural \"@count days\"\nmsgstr[0] \"@count dan\"\nmsgstr[1] \"@count dana\"\nmsgstr[2] \"@count dana\"", t('Added Croatian plural translations exported properly.'));
-  }
-
-
-  /**
-   * Imports a standalone .po file in a given language.
-   *
-   * @param $contents
-   *   Contents of the .po file to import.
-   * @param $options
-   *   Additional options to pass to the translation import form.
-   */
-  function importPoFile($contents, array $options = array()) {
-    $name = tempnam('temporary://', "po_") . '.po';
-    file_put_contents($name, $contents);
-    $options['files[file]'] = $name;
-    $this->drupalPost('admin/config/regional/translate/import', $options, t('Import'));
-    drupal_unlink($name);
-  }
-
-  /**
-   * Returns a .po file with a simple plural formula.
-   */
-  function getPoFileWithSimplePlural() {
-    return <<< EOF
-msgid ""
-msgstr ""
-"Project-Id-Version: Drupal 8\\n"
-"MIME-Version: 1.0\\n"
-"Content-Type: text/plain; charset=UTF-8\\n"
-"Content-Transfer-Encoding: 8bit\\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
-
-msgid "1 hour"
-msgid_plural "@count hours"
-msgstr[0] "1 heure"
-msgstr[1] "@count heures"
-
-msgid "Monday"
-msgstr "lundi"
-EOF;
-  }
-
-  /**
-   * Returns a .po file with a complex plural formula.
-   */
-  function getPoFileWithComplexPlural() {
-    return <<< EOF
-msgid ""
-msgstr ""
-"Project-Id-Version: Drupal 8\\n"
-"MIME-Version: 1.0\\n"
-"Content-Type: text/plain; charset=UTF-8\\n"
-"Content-Transfer-Encoding: 8bit\\n"
-"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\\n"
-
-msgid "1 hour"
-msgid_plural "@count hours"
-msgstr[0] "@count sat"
-msgstr[1] "@count sata"
-msgstr[2] "@count sati"
-
-msgid "Monday"
-msgstr "Ponedjeljak"
-EOF;
-  }
-
-  /**
-   * Returns a .po file with a missing plural formula.
-   */
-  function getPoFileWithMissingPlural() {
-    return <<< EOF
-msgid ""
-msgstr ""
-"Project-Id-Version: Drupal 8\\n"
-"MIME-Version: 1.0\\n"
-"Content-Type: text/plain; charset=UTF-8\\n"
-"Content-Transfer-Encoding: 8bit\\n"
-
-msgid "Monday"
-msgstr "lundi"
-EOF;
-  }
-
-  /**
-   * Returns a .po file with a broken plural formula.
-   */
-  function getPoFileWithBrokenPlural() {
-    return <<< EOF
-msgid ""
-msgstr ""
-"Project-Id-Version: Drupal 8\\n"
-"MIME-Version: 1.0\\n"
-"Content-Type: text/plain; charset=UTF-8\\n"
-"Content-Transfer-Encoding: 8bit\\n"
-"Plural-Forms: broken, will not parse\\n"
-
-msgid "Monday"
-msgstr "Ponedjeljak"
-EOF;
-  }
-}
-
-/**
- * Functional tests for the import of translation files.
- */
-class LocaleImportFunctionalTest extends WebTestBase {
-  public static function getInfo() {
-    return array(
-      'name' => 'Translation import',
-      'description' => 'Tests the import of locale files.',
-      'group' => 'Locale',
-    );
-  }
-
-  /**
-   * A user able to create languages and import translations.
-   */
-  protected $admin_user = NULL;
-
-  function setUp() {
-    parent::setUp(array('locale', 'dblog'));
-
-    // Set the translation file directory.
-    variable_set('locale_translate_file_directory', drupal_get_path('module', 'locale') . '/tests');
-
-    $this->admin_user = $this->drupalCreateUser(array('administer languages', 'translate interface', 'access administration pages'));
-    $this->drupalLogin($this->admin_user);
-  }
-
-  /**
-   * Test import of standalone .po files.
-   */
-  function testStandalonePoFile() {
-    // Try importing a .po file.
-    $this->importPoFile($this->getPoFile(), array(
-      'langcode' => 'fr',
-    ));
-
-    // The import should automatically create the corresponding language.
-    $this->assertRaw(t('The language %language has been created.', array('%language' => 'French')), t('The language has been automatically created.'));
-
-    // The import should have created 8 strings.
-    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 8, '%update' => 0, '%delete' => 0)), t('The translation file was successfully imported.'));
-
-    // This import should have saved plural forms to have 2 variants.
-    $locale_plurals = variable_get('locale_translation_plurals', array());
-    $this->assert($locale_plurals['fr']['plurals'] == 2, t('Plural number initialized.'));
-
-    // Ensure we were redirected correctly.
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/translate', array('absolute' => TRUE)), t('Correct page redirection.'));
-
-
-    // Try importing a .po file with invalid tags.
-    $this->importPoFile($this->getBadPoFile(), array(
-      'langcode' => 'fr',
-    ));
-
-    // The import should have created 1 string and rejected 2.
-    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 1, '%update' => 0, '%delete' => 0)), t('The translation file was successfully imported.'));
-    $skip_message = format_plural(2, 'A translation string was skipped because of disallowed or malformed HTML. <a href="@url">See the log</a> for details.', '@count translation strings were skipped because of disallowed or malformed HTML. <a href="@url">See the log</a> for details.', array('@url' => url('admin/reports/dblog')));
-    $this->assertRaw($skip_message, t('Unsafe strings were skipped.'));
-
-
-    // Try importing a .po file which doesn't exist.
-    $name = $this->randomName(16);
-    $this->drupalPost('admin/config/regional/translate/import', array(
-      'langcode' => 'fr',
-      'files[file]' => $name,
-    ), t('Import'));
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/import', array('absolute' => TRUE)), t('Correct page redirection.'));
-    $this->assertText(t('File to import not found.'), t('File to import not found message.'));
-
-
-    // Try importing a .po file with overriding strings, and ensure existing
-    // strings are kept.
-    $this->importPoFile($this->getOverwritePoFile(), array(
-      'langcode' => 'fr',
-    ));
-
-    // The import should have created 1 string.
-    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 1, '%update' => 0, '%delete' => 0)), t('The translation file was successfully imported.'));
-    // Ensure string wasn't overwritten.
-    $search = array(
-      'string' => 'Montag',
-      'language' => 'fr',
-      'translation' => 'translated',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    $this->assertText(t('No strings available.'), t('String not overwritten by imported string.'));
-
-    // This import should not have changed number of plural forms.
-    $locale_plurals = variable_get('locale_translation_plurals', array());
-    $this->assert($locale_plurals['fr']['plurals'] == 2, t('Plural numbers untouched.'));
-
-    // Try importing a .po file with overriding strings, and ensure existing
-    // strings are overwritten.
-    $this->importPoFile($this->getOverwritePoFile(), array(
-      'langcode' => 'fr',
-      'overwrite_options[not_customized]' => TRUE,
-    ));
-
-    // The import should have updated 2 strings.
-    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 0, '%update' => 2, '%delete' => 0)), t('The translation file was successfully imported.'));
-    // Ensure string was overwritten.
-    $search = array(
-      'string' => 'Montag',
-      'language' => 'fr',
-      'translation' => 'translated',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    $this->assertNoText(t('No strings available.'), t('String overwritten by imported string.'));
-    // This import should have changed number of plural forms.
-    $locale_plurals = variable_get('locale_translation_plurals', array());
-    $this->assert($locale_plurals['fr']['plurals'] == 3, t('Plural numbers changed.'));
-
-    // Importing a .po file and mark its strings as customized strings.
-    $this->importPoFile($this->getCustomPoFile(), array(
-      'langcode' => 'fr',
-      'customized' => TRUE,
-    ));
-
-    // The import should have created 6 strings.
-    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 6, '%update' => 0, '%delete' => 0)), t('The customized translation file was successfully imported.'));
-
-    // The database should now contain 6 customized strings (two imported
-    // strings are not translated).
-    $count = db_query('SELECT lid FROM {locales_target} WHERE customized = :custom', array(':custom' => 1))->rowCount();
-    $this->assertEqual($count, 6, t('Customized translations succesfully imported.'));
-
-    // Try importing a .po file with overriding strings, and ensure existing
-    // customized strings are kept.
-    $this->importPoFile($this->getCustomOverwritePoFile(), array(
-      'langcode' => 'fr',
-      'overwrite_options[not_customized]' => TRUE,
-      'overwrite_options[customized]' => FALSE,
-    ));
-
-    // The import should have created 1 string.
-    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 1, '%update' => 0, '%delete' => 0)), t('The customized translation file was successfully imported.'));
-    // Ensure string wasn't overwritten.
-    $search = array(
-      'string' => 'januari',
-      'language' => 'fr',
-      'translation' => 'translated',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    $this->assertText(t('No strings available.'), t('Customized string not overwritten by imported string.'));
-
-    // Try importing a .po file with overriding strings, and ensure existing
-    // customized strings are overwritten.
-    $this->importPoFile($this->getCustomOverwritePoFile(), array(
-      'langcode' => 'fr',
-      'overwrite_options[not_customized]' => FALSE,
-      'overwrite_options[customized]' => TRUE,
-    ));
-
-    // The import should have updated 2 strings.
-    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 0, '%update' => 2, '%delete' => 0)), t('The customized translation file was successfully imported.'));
-    // Ensure string was overwritten.
-    $search = array(
-      'string' => 'januari',
-      'language' => 'fr',
-      'translation' => 'translated',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    $this->assertNoText(t('No strings available.'), t('Customized string overwritten by imported string.'));
-
-  }
-
-  /**
-   * Test automatic import of a module's translation files.
-   */
-  function testAutomaticModuleTranslationImportLanguageEnable() {
-    // Code for the language - manually set to match the test translation file.
-    $langcode = 'xx';
-    // The English name for the language.
-    $name = $this->randomName(16);
-
-    // Create a custom language.
-    $edit = array(
-      'predefined_langcode' => 'custom',
-      'langcode' => $langcode,
-      'name' => $name,
-      'direction' => '0',
-    );
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
-
-    // Ensure the translation file was automatically imported when language was
-    // added.
-    $this->assertText(t('One translation file imported.'), t('Language file automatically imported.'));
-
-    // Ensure strings were successfully imported.
-    $search = array(
-      'string' => 'lundi',
-      'language' => $langcode,
-      'translation' => 'translated',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    $this->assertNoText(t('No strings available.'), t('String successfully imported.'));
-  }
-
-  /**
-   * Test msgctxt context support.
-   */
-  function testLanguageContext() {
-    // Try importing a .po file.
-    $this->importPoFile($this->getPoFileWithContext(), array(
-      'langcode' => 'hr',
-    ));
-
-    $this->assertIdentical(t('May', array(), array('langcode' => 'hr', 'context' => 'Long month name')), 'Svibanj', t('Long month name context is working.'));
-    $this->assertIdentical(t('May', array(), array('langcode' => 'hr')), 'Svi.', t('Default context is working.'));
-  }
-
-  /**
-   * Test empty msgstr at end of .po file see #611786.
-   */
-  function testEmptyMsgstr() {
-    $langcode = 'hu';
-
-    // Try importing a .po file.
-    $this->importPoFile($this->getPoFileWithMsgstr(), array(
-      'langcode' => $langcode,
-    ));
-
-    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 1, '%update' => 0, '%delete' => 0)), t('The translation file was successfully imported.'));
-    $this->assertIdentical(t('Operations', array(), array('langcode' => $langcode)), 'Műveletek', t('String imported and translated.'));
-
-    // Try importing a .po file.
-    $this->importPoFile($this->getPoFileWithEmptyMsgstr(), array(
-      'langcode' => $langcode,
-      'overwrite_options[not_customized]' => TRUE,
-    ));
-    $this->assertRaw(t('The translation was successfully imported. There are %number newly created translated strings, %update strings were updated and %delete strings were removed.', array('%number' => 0, '%update' => 0, '%delete' => 1)), t('The translation file was successfully imported.'));
-    // This is the language indicator on the translation search screen for
-    // untranslated strings.
-    $language_indicator = "<em class=\"locale-untranslated\">$langcode</em> ";
-    $str = "Operations";
-    $search = array(
-      'string' => $str,
-      'language' => 'all',
-      'translation' => 'all',
-    );
-    $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
-    // assertText() seems to remove the input field where $str always could be
-    // found, so this is not a false assert.
-    $this->assertText($str, t('Search found the string.'));
-    $this->assertRaw($language_indicator, t('String is untranslated again.'));
-  }
-
-  /**
-   * Helper function: import a standalone .po file in a given language.
-   *
-   * @param $contents
-   *   Contents of the .po file to import.
-   * @param $options
-   *   Additional options to pass to the translation import form.
-   */
-  function importPoFile($contents, array $options = array()) {
-    $name = tempnam('temporary://', "po_") . '.po';
-    file_put_contents($name, $contents);
-    $options['files[file]'] = $name;
-    $this->drupalPost('admin/config/regional/translate/import', $options, t('Import'));
-    drupal_unlink($name);
-  }
-
-  /**
-   * Helper function that returns a proper .po file.
-   */
-  function getPoFile() {
-    return <<< EOF
-msgid ""
-msgstr ""
-"Project-Id-Version: Drupal 8\\n"
-"MIME-Version: 1.0\\n"
-"Content-Type: text/plain; charset=UTF-8\\n"
-"Content-Transfer-Encoding: 8bit\\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
-
-msgid "One sheep"
-msgid_plural "@count sheep"
-msgstr[0] "un mouton"
-msgstr[1] "@count moutons"
-
-msgid "Monday"
-msgstr "lundi"
-
-msgid "Tuesday"
-msgstr "mardi"
-
-msgid "Wednesday"
-msgstr "mercredi"
-
-msgid "Thursday"
-msgstr "jeudi"
-
-msgid "Friday"
-msgstr "vendredi"
-
-msgid "Saturday"
-msgstr "samedi"
-
-msgid "Sunday"
-msgstr "dimanche"
-EOF;
-  }
-
-  /**
-   * Helper function that returns a bad .po file.
-   */
-  function getBadPoFile() {
-    return <<< EOF
-msgid ""
-msgstr ""
-"Project-Id-Version: Drupal 8\\n"
-"MIME-Version: 1.0\\n"
-"Content-Type: text/plain; charset=UTF-8\\n"
-"Content-Transfer-Encoding: 8bit\\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
-
-msgid "Save configuration"
-msgstr "Enregistrer la configuration"
-
-msgid "edit"
-msgstr "modifier<img SRC="javascript:alert(\'xss\');">"
-
-msgid "delete"
-msgstr "supprimer<script>alert('xss');</script>"
-
-EOF;
-  }
-
-  /**
-   * Helper function that returns a proper .po file for testing.
-   */
-  function getOverwritePoFile() {
-    return <<< EOF
-msgid ""
-msgstr ""
-"Project-Id-Version: Drupal 8\\n"
-"MIME-Version: 1.0\\n"
-"Content-Type: text/plain; charset=UTF-8\\n"
-"Content-Transfer-Encoding: 8bit\\n"
-"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\\n"
-
-msgid "Monday"
-msgstr "Montag"
-
-msgid "Day"
-msgstr "Jour"
-EOF;
-  }
-
-  /**
-   * Helper function that returns a .po file which strings will be marked
-   * as customized.
-   */
-  function getCustomPoFile() {
-    return <<< EOF
-msgid ""
-msgstr ""
-"Project-Id-Version: Drupal 8\\n"
-"MIME-Version: 1.0\\n"
-"Content-Type: text/plain; charset=UTF-8\\n"
-"Content-Transfer-Encoding: 8bit\\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
-
-msgid "One dog"
-msgid_plural "@count dogs"
-msgstr[0] "un chien"
-msgstr[1] "@count chiens"
-
-msgid "January"
-msgstr "janvier"
-
-msgid "February"
-msgstr "février"
-
-msgid "March"
-msgstr "mars"
-
-msgid "April"
-msgstr "avril"
-
-msgid "June"
-msgstr "juin"
-EOF;
-  }
-
-  /**
-   * Helper function that returns a .po file for testing customized strings.
-   */
-  function getCustomOverwritePoFile() {
-    return <<< EOF
-msgid ""
-msgstr ""
-"Project-Id-Version: Drupal 8\\n"
-"MIME-Version: 1.0\\n"
-"Content-Type: text/plain; charset=UTF-8\\n"
-"Content-Transfer-Encoding: 8bit\\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
-
-msgid "January"
-msgstr "januari"
-
-msgid "February"
-msgstr "februari"
-
-msgid "July"
-msgstr "juillet"
-EOF;
-  }
-
-  /**
-   * Helper function that returns a .po file with context.
-   */
-  function getPoFileWithContext() {
-    // Croatian (code hr) is one the the languages that have a different
-    // form for the full name and the abbreviated name for the month May.
-    return <<< EOF
-msgid ""
-msgstr ""
-"Project-Id-Version: Drupal 8\\n"
-"MIME-Version: 1.0\\n"
-"Content-Type: text/plain; charset=UTF-8\\n"
-"Content-Transfer-Encoding: 8bit\\n"
-"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\\n"
-
-msgctxt "Long month name"
-msgid "May"
-msgstr "Svibanj"
-
-msgid "May"
-msgstr "Svi."
-EOF;
-  }
-
-  /**
-   * Helper function that returns a .po file with an empty last item.
-   */
-  function getPoFileWithEmptyMsgstr() {
-    return <<< EOF
-msgid ""
-msgstr ""
-"Project-Id-Version: Drupal 8\\n"
-"MIME-Version: 1.0\\n"
-"Content-Type: text/plain; charset=UTF-8\\n"
-"Content-Transfer-Encoding: 8bit\\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
-
-msgid "Operations"
-msgstr ""
-
-EOF;
-  }
-  /**
-   * Helper function that returns a .po file with an empty last item.
-   */
-  function getPoFileWithMsgstr() {
-    return <<< EOF
-msgid ""
-msgstr ""
-"Project-Id-Version: Drupal 8\\n"
-"MIME-Version: 1.0\\n"
-"Content-Type: text/plain; charset=UTF-8\\n"
-"Content-Transfer-Encoding: 8bit\\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
-
-msgid "Operations"
-msgstr "Műveletek"
-
-msgid "Will not appear in Drupal core, so we can ensure the test passes"
-msgstr ""
-
-EOF;
-  }
-
-}
-
-/**
- * Functional tests for the export of translation files.
- */
-class LocaleExportFunctionalTest extends WebTestBase {
-  public static function getInfo() {
-    return array(
-      'name' => 'Translation export',
-      'description' => 'Tests the exportation of locale files.',
-      'group' => 'Locale',
-    );
-  }
-
-  /**
-   * A user able to create languages and export translations.
-   */
-  protected $admin_user = NULL;
-
-  function setUp() {
-    parent::setUp('locale');
-
-    $this->admin_user = $this->drupalCreateUser(array('administer languages', 'translate interface', 'access administration pages'));
-    $this->drupalLogin($this->admin_user);
-  }
-
-  /**
-   * Test exportation of translations.
-   */
-  function testExportTranslation() {
-    // First import some known translations.
-    // This will also automatically enable the 'fr' language.
-    $name = tempnam('temporary://', "po_") . '.po';
-    file_put_contents($name, $this->getPoFile());
-    $this->drupalPost('admin/config/regional/translate/import', array(
-      'langcode' => 'fr',
-      'files[file]' => $name,
-    ), t('Import'));
-    drupal_unlink($name);
-
-    // Get the French translations.
-    $this->drupalPost('admin/config/regional/translate/export', array(
-      'langcode' => 'fr',
-    ), t('Export'));
-
-    // Ensure we have a translation file.
-    $this->assertRaw('# French translation of Drupal', t('Exported French translation file.'));
-    // Ensure our imported translations exist in the file.
-    $this->assertRaw('msgstr "lundi"', t('French translations present in exported file.'));
-
-    // Import some more French translations which will be marked as customized.
-    $name = tempnam('temporary://', "po2_") . '.po';
-    file_put_contents($name, $this->getCustomPoFile());
-    $this->drupalPost('admin/config/regional/translate/import', array(
-      'langcode' => 'fr',
-      'files[file]' => $name,
-      'customized' => 1,
-    ), t('Import'));
-    drupal_unlink($name);
-
-    // We can't import a string with an empty translation, but calling
-    // locale() for an new string creates an entry in the locales_source table.
-    locale('February', NULL, 'fr');
-
-    // Export only customized French translations.
-    $this->drupalPost('admin/config/regional/translate/export', array(
-      'langcode' => 'fr',
-      'content_options[not_customized]' => FALSE,
-      'content_options[customized]' => TRUE,
-      'content_options[not_translated]' => FALSE,
-    ), t('Export'));
-
-    // Ensure we have a translation file.
-    $this->assertRaw('# French translation of Drupal', t('Exported French translation file with only customized strings.'));
-    // Ensure the customized translations exist in the file.
-    $this->assertRaw('msgstr "janvier"', t('French custom translation present in exported file.'));
-    // Ensure no untranslated strings exist in the file.
-    $this->assertNoRaw('msgid "February"', t('Untranslated string not present in exported file.'));
-
-    // Export only untranslated French translations.
-    $this->drupalPost('admin/config/regional/translate/export', array(
-      'langcode' => 'fr',
-      'content_options[not_customized]' => FALSE,
-      'content_options[customized]' => FALSE,
-      'content_options[not_translated]' => TRUE,
-    ), t('Export'));
-
-    // Ensure we have a translation file.
-    $this->assertRaw('# French translation of Drupal', t('Exported French translation file with only untranslated strings.'));
-    // Ensure no customized translations exist in the file.
-    $this->assertNoRaw('msgstr "janvier"', t('French custom translation not present in exported file.'));
-    // Ensure the untranslated strings exist in the file.
-    $this->assertRaw('msgid "February"', t('Untranslated string present in exported file.'));
-  }
-
-  /**
-   * Test exportation of translation template file.
-   */
-  function testExportTranslationTemplateFile() {
-    // Get the translation template file.
-    $this->drupalPost('admin/config/regional/translate/export', array(), t('Export'));
-    // Ensure we have a translation file.
-    $this->assertRaw('# LANGUAGE translation of PROJECT', t('Exported translation template file.'));
-  }
-
-  /**
-   * Helper function that returns a proper .po file.
-   */
-  function getPoFile() {
-    return <<< EOF
-msgid ""
-msgstr ""
-"Project-Id-Version: Drupal 8\\n"
-"MIME-Version: 1.0\\n"
-"Content-Type: text/plain; charset=UTF-8\\n"
-"Content-Transfer-Encoding: 8bit\\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
-
-msgid "Monday"
-msgstr "lundi"
-EOF;
-  }
-
-  /**
-   * Helper function that returns a .po file which strings will be marked
-   * as customized.
-   */
-  function getCustomPoFile() {
-    return <<< EOF
-msgid ""
-msgstr ""
-"Project-Id-Version: Drupal 8\\n"
-"MIME-Version: 1.0\\n"
-"Content-Type: text/plain; charset=UTF-8\\n"
-"Content-Transfer-Encoding: 8bit\\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
-
-msgid "January"
-msgstr "janvier"
-EOF;
-  }
-
-}
-
-/**
- * Tests for the st() function.
- */
-class LocaleInstallTest extends WebTestBase {
-  public static function getInfo() {
-    return array(
-      'name' => 'String translation using st()',
-      'description' => 'Tests that st() works like t().',
-      'group' => 'Locale',
-    );
-  }
-
-  function setUp() {
-    parent::setUp('locale');
-
-    // st() lives in install.inc, so ensure that it is loaded for all tests.
-    require_once DRUPAL_ROOT . '/core/includes/install.inc';
-  }
-
-  /**
-   * Verify that function signatures of t() and st() are equal.
-   */
-  function testFunctionSignatures() {
-    $reflector_t = new ReflectionFunction('t');
-    $reflector_st = new ReflectionFunction('st');
-    $this->assertEqual($reflector_t->getParameters(), $reflector_st->getParameters(), t('Function signatures of t() and st() are equal.'));
-  }
-}
-
-/**
- * Locale uninstall with English UI functional test.
- */
-class LocaleUninstallFunctionalTest extends WebTestBase {
-  public static function getInfo() {
-    return array(
-      'name' => 'Locale uninstall (EN)',
-      'description' => 'Tests the uninstall process using the built-in UI language.',
-      'group' => 'Locale',
-    );
-  }
-
-  /**
-   * The default language set for the UI before uninstall.
-   */
-  protected $language;
-
-  function setUp() {
-    parent::setUp(array('node', 'locale'));
-    $this->langcode = 'en';
-
-    // Create Article node type.
-    $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
-  }
-
-  /**
-   * Check if the values of the Locale variables are correct after uninstall.
-   */
-  function testUninstallProcess() {
-    $locale_module = array('locale', 'language');
-
-    $language = (object) array(
-      'langcode' => 'fr',
-      'name' => 'French',
-      'default' => $this->langcode == 'fr',
-    );
-    language_save($language);
-
-    // Check the UI language.
-    drupal_language_initialize();
-    $this->assertEqual(drupal_container()->get(LANGUAGE_TYPE_INTERFACE)->langcode, $this->langcode, t('Current language: %lang', array('%lang' => drupal_container()->get(LANGUAGE_TYPE_INTERFACE)->langcode)));
-
-    // Enable multilingual workflow option for articles.
-    variable_set('node_type_language_article', 1);
-
-    // Change JavaScript translations directory.
-    variable_set('locale_js_directory', 'js_translations');
-
-    // Build the JavaScript translation file for French.
-    $user = $this->drupalCreateUser(array('translate interface', 'access administration pages'));
-    $this->drupalLogin($user);
-    $this->drupalGet('admin/config/regional/translate/translate');
-    $string = db_query('SELECT min(lid) AS lid FROM {locales_source} WHERE location LIKE :location', array(
-      ':location' => '%.js%',
-    ))->fetchObject();
-    $edit = array('translations[fr][0]' => 'french translation');
-    $this->drupalPost('admin/config/regional/translate/edit/' . $string->lid, $edit, t('Save translations'));
-    _locale_rebuild_js('fr');
-    $locale_javascripts = variable_get('locale_translation_javascript', array());
-    $js_file = 'public://' . variable_get('locale_js_directory', 'languages') . '/fr_' . $locale_javascripts['fr'] . '.js';
-    $this->assertTrue($result = file_exists($js_file), t('JavaScript file created: %file', array('%file' => $result ? $js_file : t('none'))));
-
-    // Disable string caching.
-    variable_set('locale_cache_strings', 0);
-
-    // Change language negotiation options.
-    drupal_load('module', 'locale');
-    variable_set('language_types', language_types_get_default() + array('language_custom' => TRUE));
-    variable_set('language_negotiation_' . LANGUAGE_TYPE_INTERFACE, language_language_negotiation_info());
-    variable_set('language_negotiation_' . LANGUAGE_TYPE_CONTENT, language_language_negotiation_info());
-    variable_set('language_negotiation_' . LANGUAGE_TYPE_URL, language_language_negotiation_info());
-
-    // Change language negotiation settings.
-    variable_set('language_negotiation_url_part', LANGUAGE_NEGOTIATION_URL_PREFIX);
-    variable_set('language_negotiation_session_param', TRUE);
-
-    // Uninstall Locale.
-    module_disable($locale_module);
-    drupal_uninstall_modules($locale_module);
-
-    // Visit the front page.
-    $this->drupalGet('');
-
-    // Check the init language logic.
-    drupal_language_initialize();
-    $this->assertEqual(drupal_container()->get(LANGUAGE_TYPE_INTERFACE)->langcode, 'en', t('Language after uninstall: %lang', array('%lang' => drupal_container()->get(LANGUAGE_TYPE_INTERFACE)->langcode)));
-
-    // Check JavaScript files deletion.
-    $this->assertTrue($result = !file_exists($js_file), t('JavaScript file deleted: %file', array('%file' => $result ? $js_file : t('found'))));
-
-    // Check language count.
-    $language_count = variable_get('language_count', 1);
-    $this->assertEqual($language_count, 1, t('Language count: %count', array('%count' => $language_count)));
-
-    // Check language negotiation.
-    require_once DRUPAL_ROOT . '/core/includes/language.inc';
-    $this->assertTrue(count(language_types_get_all()) == count(language_types_get_default()), t('Language types reset'));
-    $language_negotiation = language_negotiation_method_get_first(LANGUAGE_TYPE_INTERFACE) == LANGUAGE_NEGOTIATION_DEFAULT;
-    $this->assertTrue($language_negotiation, t('Interface language negotiation: %setting', array('%setting' => t($language_negotiation ? 'none' : 'set'))));
-    $language_negotiation = language_negotiation_method_get_first(LANGUAGE_TYPE_CONTENT) == LANGUAGE_NEGOTIATION_DEFAULT;
-    $this->assertTrue($language_negotiation, t('Content language negotiation: %setting', array('%setting' => t($language_negotiation ? 'none' : 'set'))));
-    $language_negotiation = language_negotiation_method_get_first(LANGUAGE_TYPE_URL) == LANGUAGE_NEGOTIATION_DEFAULT;
-    $this->assertTrue($language_negotiation, t('URL language negotiation: %setting', array('%setting' => t($language_negotiation ? 'none' : 'set'))));
-
-    // Check language negotiation method settings.
-    $this->assertFalse(variable_get('language_negotiation_url_part', FALSE), t('URL language negotiation method indicator settings cleared.'));
-    $this->assertFalse(variable_get('language_negotiation_session_param', FALSE), t('Visit language negotiation method settings cleared.'));
-
-    // Check JavaScript parsed.
-    $javascript_parsed_count = count(variable_get('javascript_parsed', array()));
-    $this->assertEqual($javascript_parsed_count, 0, t('JavaScript parsed count: %count', array('%count' => $javascript_parsed_count)));
-
-    // Check JavaScript translations directory.
-    $locale_js_directory = variable_get('locale_js_directory', 'languages');
-    $this->assertEqual($locale_js_directory, 'languages', t('JavaScript translations directory: %dir', array('%dir' => $locale_js_directory)));
-
-    // Check string caching.
-    $locale_cache_strings = variable_get('locale_cache_strings', 1);
-    $this->assertEqual($locale_cache_strings, 1, t('String caching: %status', array('%status' => t($locale_cache_strings ? 'enabled': 'disabled'))));
-  }
-}
-
-/**
- * Locale uninstall with French UI functional test.
- *
- * Because this class extends LocaleUninstallFunctionalTest, it doesn't require a new
- * test of its own. Rather, it switches the default UI language in setUp and then
- * runs the testUninstallProcess (which it inherits from LocaleUninstallFunctionalTest)
- * to test with this new language.
- */
-class LocaleUninstallFrenchFunctionalTest extends LocaleUninstallFunctionalTest {
-  public static function getInfo() {
-    return array(
-      'name' => 'Locale uninstall (FR)',
-      'description' => 'Tests the uninstall process using French as interface language.',
-      'group' => 'Locale',
-    );
-  }
-
-  function setUp() {
-    parent::setUp();
-    $this->langcode = 'fr';
-  }
-}
-
-/**
- * Functional tests for configuring a different path alias per language.
- */
-class LocalePathFunctionalTest extends WebTestBase {
-  public static function getInfo() {
-    return array(
-      'name' => 'Path language settings',
-      'description' => 'Checks you can configure a language for individual url aliases.',
-      'group' => 'Locale',
-    );
-  }
-
-  function setUp() {
-    parent::setUp(array('node', 'locale', 'path'));
-
-    $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
-    variable_set('site_frontpage', 'node');
-  }
-
-  /**
-   * Test if a language can be associated with a path alias.
-   */
-  function testPathLanguageConfiguration() {
-    global $base_url;
-
-    // User to add and remove language.
-    $admin_user = $this->drupalCreateUser(array('administer languages', 'create page content', 'administer url aliases', 'create url aliases', 'access administration pages'));
-
-    // Add custom language.
-    $this->drupalLogin($admin_user);
-    // Code for the language.
-    $langcode = 'xx';
-    // The English name for the language.
-    $name = $this->randomName(16);
-    // The domain prefix.
-    $prefix = $langcode;
-    $edit = array(
-      'predefined_langcode' => 'custom',
-      'langcode' => $langcode,
-      'name' => $name,
-      'direction' => '0',
-    );
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
-
-    // Set path prefix.
-    $edit = array( "prefix[$langcode]" => $prefix );
-    $this->drupalPost('admin/config/regional/language/detection/url', $edit, t('Save configuration'));
-
-    // Check that the "xx" front page is readily available because path prefix
-    // negotiation is pre-configured.
-    $this->drupalGet($prefix);
-    $this->assertText(t('Welcome to Drupal'), t('The "xx" front page is readibly available.'));
-
-    // Create a node.
-    $node = $this->drupalCreateNode(array('type' => 'page'));
-
-    // Create a path alias in default language (English).
-    $path = 'admin/config/search/path/add';
-    $english_path = $this->randomName(8);
-    $edit = array(
-      'source'   => 'node/' . $node->nid,
-      'alias'    => $english_path,
-      'langcode' => 'en',
-    );
-    $this->drupalPost($path, $edit, t('Save'));
-
-    // Create a path alias in new custom language.
-    $custom_language_path = $this->randomName(8);
-    $edit = array(
-      'source'   => 'node/' . $node->nid,
-      'alias'    => $custom_language_path,
-      'langcode' => $langcode,
-    );
-    $this->drupalPost($path, $edit, t('Save'));
-
-    // Confirm English language path alias works.
-    $this->drupalGet($english_path);
-    $this->assertText($node->title, t('English alias works.'));
-
-    // Confirm custom language path alias works.
-    $this->drupalGet($prefix . '/' . $custom_language_path);
-    $this->assertText($node->title, t('Custom language alias works.'));
-
-    // Create a custom path.
-    $custom_path = $this->randomName(8);
-
-    // Check priority of language for alias by source path.
-    $edit = array(
-      'source'   => 'node/' . $node->nid,
-      'alias'    => $custom_path,
-      'langcode' => LANGUAGE_NOT_SPECIFIED,
-    );
-    path_save($edit);
-    $lookup_path = drupal_lookup_path('alias', 'node/' . $node->nid, 'en');
-    $this->assertEqual($english_path, $lookup_path, t('English language alias has priority.'));
-    // Same check for language 'xx'.
-    $lookup_path = drupal_lookup_path('alias', 'node/' . $node->nid, $prefix);
-    $this->assertEqual($custom_language_path, $lookup_path, t('Custom language alias has priority.'));
-    path_delete($edit);
-
-    // Create language nodes to check priority of aliases.
-    $first_node = $this->drupalCreateNode(array('type' => 'page', 'promote' => 1));
-    $second_node = $this->drupalCreateNode(array('type' => 'page', 'promote' => 1));
-
-    // Assign a custom path alias to the first node with the English language.
-    $edit = array(
-      'source'   => 'node/' . $first_node->nid,
-      'alias'    => $custom_path,
-      'langcode' => 'en',
-    );
-    path_save($edit);
-
-    // Assign a custom path alias to second node with LANGUAGE_NOT_SPECIFIED.
-    $edit = array(
-      'source'   => 'node/' . $second_node->nid,
-      'alias'    => $custom_path,
-      'langcode' => LANGUAGE_NOT_SPECIFIED,
-    );
-    path_save($edit);
-
-    // Test that both node titles link to our path alias.
-    $this->drupalGet('<front>');
-    $custom_path_url = base_path() . $GLOBALS['script_path'] . $custom_path;
-    $elements = $this->xpath('//a[@href=:href and .=:title]', array(':href' => $custom_path_url, ':title' => $first_node->title));
-    $this->assertTrue(!empty($elements), t('First node links to the path alias.'));
-    $elements = $this->xpath('//a[@href=:href and .=:title]', array(':href' => $custom_path_url, ':title' => $second_node->title));
-    $this->assertTrue(!empty($elements), t('Second node links to the path alias.'));
-
-    // Confirm that the custom path leads to the first node.
-    $this->drupalGet($custom_path);
-    $this->assertText($first_node->title, t('Custom alias returns first node.'));
-
-    // Confirm that the custom path with prefix leads to the second node.
-    $this->drupalGet($prefix . '/' . $custom_path);
-    $this->assertText($second_node->title, t('Custom alias with prefix returns second node.'));
-
-  }
-}
-
-/**
- * Functional tests for multilingual support on nodes.
- */
-class LocaleContentFunctionalTest extends WebTestBase {
-  protected $profile = 'standard';
-
-  public static function getInfo() {
-    return array(
-      'name' => 'Content language settings',
-      'description' => 'Checks you can enable multilingual support on content types and configure a language for a node.',
-      'group' => 'Locale',
-    );
-  }
-
-  function setUp() {
-    parent::setUp('locale');
-  }
-
-  /**
-   * Verifies that machine name fields are always LTR.
-   */
-  function testMachineNameLTR() {
-    // User to add and remove language.
-    $admin_user = $this->drupalCreateUser(array('administer languages', 'administer content types', 'access administration pages'));
-
-    // Log in as admin.
-    $this->drupalLogin($admin_user);
-
-    // Verify that the machine name field is LTR for a new content type.
-    $this->drupalGet('admin/structure/types/add');
-    $this->assertFieldByXpath('//input[@name="type" and @dir="ltr"]', NULL, 'The machine name field is LTR when no additional language is configured.');
-
-    // Install the Arabic language (which is RTL) and configure as the default.
-    $edit = array();
-    $edit['predefined_langcode'] = 'ar';
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
-
-    $edit = array();
-    $edit['site_default'] = 'ar';
-    $this->drupalPost(NULL, $edit, t('Save configuration'));
-
-    // Verify that the machine name field is still LTR for a new content type.
-    $this->drupalGet('admin/structure/types/add');
-    $this->assertFieldByXpath('//input[@name="type" and @dir="ltr"]', NULL, 'The machine name field is LTR when the default language is RTL.');
-  }
-
-  /**
-   * Test if a content type can be set to multilingual and language is present.
-   */
-  function testContentTypeLanguageConfiguration() {
-    global $base_url;
-
-    // User to add and remove language.
-    $admin_user = $this->drupalCreateUser(array('administer languages', 'administer content types', 'access administration pages'));
-    // User to create a node.
-    $web_user = $this->drupalCreateUser(array('create article content', 'create page content', 'edit any page content'));
-
-    // Add custom language.
-    $this->drupalLogin($admin_user);
-    // Code for the language.
-    $langcode = 'xx';
-    // The English name for the language.
-    $name = $this->randomName(16);
-    $edit = array(
-      'predefined_langcode' => 'custom',
-      'langcode' => $langcode,
-      'name' => $name,
-      'direction' => '0',
-    );
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
-
-    // Set "Basic page" content type to use multilingual support.
-    $this->drupalGet('admin/structure/types/manage/page');
-    $this->assertText(t('Multilingual support'), t('Multilingual support fieldset present on content type configuration form.'));
-    $edit = array(
-      'node_type_language' => 1,
-    );
-    $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
-    $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.'));
-    $this->drupalLogout();
-
-    // Verify language selection is not present on add article form.
-    $this->drupalLogin($web_user);
-    $this->drupalGet('node/add/article');
-    // Verify language select list is not present.
-    $this->assertNoFieldByName('language', NULL, t('Language select not present on add article form.'));
-
-    // Verify language selection appears on add "Basic page" form.
-    $this->drupalGet('node/add/page');
-    // Verify language select list is present.
-    $this->assertFieldByName('langcode', NULL, t('Language select present on add Basic page form.'));
-    // Ensure language appears.
-    $this->assertText($name, t('Language present.'));
-
-    // Create "Basic page" content.
-    $node_title = $this->randomName();
-    $node_body =  $this->randomName();
-    $edit = array(
-      'type' => 'page',
-      'title' => $node_title,
-      'body' => array($langcode => array(array('value' => $node_body))),
-      'langcode' => $langcode,
-    );
-    $node = $this->drupalCreateNode($edit);
-    // Edit the content and ensure correct language is selected.
-    $path = 'node/' . $node->nid . '/edit';
-    $this->drupalGet($path);
-    $this->assertRaw('<option value="' . $langcode . '" selected="selected">' .  $name . '</option>', t('Correct language selected.'));
-    // Ensure we can change the node language.
-    $edit = array(
-      'langcode' => 'en',
-    );
-    $this->drupalPost($path, $edit, t('Save'));
-    $this->assertRaw(t('%title has been updated.', array('%title' => $node_title)), t('Basic page content updated.'));
-
-    $this->drupalLogout();
-  }
-
-  /**
-   * Test if a dir and lang tags exist in node's attributes.
-   */
-  function testContentTypeDirLang() {
-    // User to add and remove language.
-    $admin_user = $this->drupalCreateUser(array('administer languages', 'administer content types', 'access administration pages'));
-    // User to create a node.
-    $web_user = $this->drupalCreateUser(array('create article content', 'edit own article content'));
-
-    // Login as admin.
-    $this->drupalLogin($admin_user);
-
-    // Install Arabic language.
-    $edit = array();
-    $edit['predefined_langcode'] = 'ar';
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
-
-    // Install Spanish language.
-    $edit = array();
-    $edit['predefined_langcode'] = 'es';
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
-
-    // Set "Article" content type to use multilingual support.
-    $this->drupalGet('admin/structure/types/manage/article');
-    $edit = array(
-      'node_type_language' => 1,
-    );
-    $this->drupalPost('admin/structure/types/manage/article', $edit, t('Save content type'));
-    $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Article')), t('Article content type has been updated.'));
-    $this->drupalLogout();
-
-    // Login as web user to add new article.
-    $this->drupalLogin($web_user);
-
-    // Create three nodes: English, Arabic and Spanish.
-    $node_en = $this->createNodeArticle('en');
-    $node_ar = $this->createNodeArticle('ar');
-    $node_es = $this->createNodeArticle('es');
-
-    $this->drupalGet('node');
-
-    // Check if English node does not have lang tag.
-    $pattern = '|id="node-' . $node_en->nid . '"[^<>]*lang="en"|';
-    $this->assertNoPattern($pattern, t('The lang tag has not been assigned to the English node.'));
-
-    // Check if English node does not have dir tag.
-    $pattern = '|id="node-' . $node_en->nid . '"[^<>]*dir="ltr"|';
-    $this->assertNoPattern($pattern, t('The dir tag has not been assigned to the English node.'));
-
-    // Check if Arabic node has lang="ar" & dir="rtl" tags.
-    $pattern = '|id="node-' . $node_ar->nid . '"[^<>]*lang="ar" dir="rtl"|';
-    $this->assertPattern($pattern, t('The lang and dir tags have been assigned correctly to the Arabic node.'));
-
-    // Check if Spanish node has lang="es" tag.
-    $pattern = '|id="node-' . $node_es->nid . '"[^<>]*lang="es"|';
-    $this->assertPattern($pattern, t('The lang tag has been assigned correctly to the Spanish node.'));
-
-    // Check if Spanish node does not have dir="ltr" tag.
-    $pattern = '|id="node-' . $node_es->nid . '"[^<>]*lang="es" dir="ltr"|';
-    $this->assertNoPattern($pattern, t('The dir tag has not been assigned to the Spanish node.'));
-
-    $this->drupalLogout();
-  }
-
-  /**
-   * Create node in a specific language.
-   */
-  protected function createNodeArticle($langcode) {
-    $this->drupalGet('node/add/article');
-    $node_title = $this->randomName();
-    $node_body =  $this->randomName();
-    $edit = array(
-      'type' => 'article',
-      'title' => $node_title,
-      'body' => array($langcode => array(array('value' => $node_body))),
-      'langcode' => $langcode,
-      'promote' => 1,
-    );
-    return $this->drupalCreateNode($edit);
-  }
-}
-
-/**
- * Functional test for multilingual fields.
- */
-class LocaleMultilingualFieldsFunctionalTest extends WebTestBase {
-  public static function getInfo() {
-    return array(
-      'name' => 'Multilingual fields',
-      'description' => 'Test multilingual support for fields.',
-      'group' => 'Locale',
-    );
-  }
-
-  function setUp() {
-    parent::setUp(array('node', 'locale'));
-
-    // Create Basic page node type.
-    $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
-
-    // Setup users.
-    $admin_user = $this->drupalCreateUser(array('administer languages', 'administer content types', 'access administration pages', 'create page content', 'edit own page content'));
-    $this->drupalLogin($admin_user);
-
-    // Add a new language.
-    $language = (object) array(
-      'langcode' => 'it',
-      'name' => 'Italian',
-    );
-    language_save($language);
-
-    // Enable URL language detection and selection.
-    $edit = array('language_interface[enabled][language-url]' => '1');
-    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
-
-    // Set "Basic page" content type to use multilingual support.
-    $edit = array(
-      'node_type_language' => 1,
-    );
-    $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
-    $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.'));
-
-    // Make node body translatable.
-    $field = field_info_field('body');
-    $field['translatable'] = TRUE;
-    field_update_field($field);
-  }
-
-  /**
-   * Test if field languages are correctly set through the node form.
-   */
-  function testMultilingualNodeForm() {
-    // Create "Basic page" content.
-    $langcode = LANGUAGE_NOT_SPECIFIED;
-    $title_key = "title";
-    $title_value = $this->randomName(8);
-    $body_key = "body[$langcode][0][value]";
-    $body_value = $this->randomName(16);
-
-    // Create node to edit.
-    $edit = array();
-    $edit[$title_key] = $title_value;
-    $edit[$body_key] = $body_value;
-    $edit['langcode'] = 'en';
-    $this->drupalPost('node/add/page', $edit, t('Save'));
-
-    // Check that the node exists in the database.
-    $node = $this->drupalGetNodeByTitle($edit[$title_key]);
-    $this->assertTrue($node, t('Node found in database.'));
-
-    $assert = isset($node->body['en']) && !isset($node->body[LANGUAGE_NOT_SPECIFIED]) && $node->body['en'][0]['value'] == $body_value;
-    $this->assertTrue($assert, t('Field language correctly set.'));
-
-    // Change node language.
-    $this->drupalGet("node/$node->nid/edit");
-    $edit = array(
-      $title_key => $this->randomName(8),
-      'langcode' => 'it'
-    );
-    $this->drupalPost(NULL, $edit, t('Save'));
-    $node = $this->drupalGetNodeByTitle($edit[$title_key]);
-    $this->assertTrue($node, t('Node found in database.'));
-
-    $assert = isset($node->body['it']) && !isset($node->body['en']) && $node->body['it'][0]['value'] == $body_value;
-    $this->assertTrue($assert, t('Field language correctly changed.'));
-
-    // Enable content language URL detection.
-    language_negotiation_set(LANGUAGE_TYPE_CONTENT, array(LANGUAGE_NEGOTIATION_URL => 0));
-
-    // Test multilingual field language fallback logic.
-    $this->drupalGet("it/node/$node->nid");
-    $this->assertRaw($body_value, t('Body correctly displayed using Italian as requested language'));
-
-    $this->drupalGet("node/$node->nid");
-    $this->assertRaw($body_value, t('Body correctly displayed using English as requested language'));
-  }
-
-  /*
-   * Test multilingual field display settings.
-   */
-  function testMultilingualDisplaySettings() {
-    // Create "Basic page" content.
-    $langcode = LANGUAGE_NOT_SPECIFIED;
-    $title_key = "title";
-    $title_value = $this->randomName(8);
-    $body_key = "body[$langcode][0][value]";
-    $body_value = $this->randomName(16);
-
-    // Create node to edit.
-    $edit = array();
-    $edit[$title_key] = $title_value;
-    $edit[$body_key] = $body_value;
-    $edit['langcode'] = 'en';
-    $this->drupalPost('node/add/page', $edit, t('Save'));
-
-    // Check that the node exists in the database.
-    $node = $this->drupalGetNodeByTitle($edit[$title_key]);
-    $this->assertTrue($node, t('Node found in database.'));
-
-    // Check if node body is showed.
-    $this->drupalGet("node/$node->nid");
-    $body = $this->xpath('//article[@id=:id]//div[@class=:class]/descendant::p', array(
-      ':id' => 'node-' . $node->nid,
-      ':class' => 'content',
-    ));
-    $this->assertEqual(current($body), $node->body['en'][0]['value'], 'Node body found.');
-  }
-}
-
-/**
- * Functional tests for comment language.
- */
-class LocaleCommentLanguageFunctionalTest extends WebTestBase {
-  protected $profile = 'standard';
-
-  public static function getInfo() {
-    return array(
-      'name' => 'Comment language',
-      'description' => 'Tests for comment language.',
-      'group' => 'Locale',
-    );
-  }
-
-  function setUp() {
-    // We also use language_test module here to be able to turn on content
-    // language negotiation. Drupal core does not provide a way in itself
-    // to do that.
-    parent::setUp('locale', 'language_test');
-
-    // Create and login user.
-    $admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer languages', 'access administration pages', 'administer content types', 'create article content'));
-    $this->drupalLogin($admin_user);
-
-    // Add language.
-    $edit = array('predefined_langcode' => 'fr');
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
-
-    // Set "Article" content type to use multilingual support.
-    $edit = array('node_type_language' => 1);
-    $this->drupalPost('admin/structure/types/manage/article', $edit, t('Save content type'));
-
-    // Enable content language negotiation UI.
-    variable_set('language_test_content_language_type', TRUE);
-
-    // Set interface language detection to user and content language detection
-    // to URL. Disable inheritance from interface language to ensure content
-    // language will fall back to the default language if no URL language can be
-    // detected.
-    $edit = array(
-      'language_interface[enabled][language-user]' => TRUE,
-      'language_content[enabled][language-url]' => TRUE,
-      'language_content[enabled][language-interface]' => FALSE,
-    );
-    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
-
-    // Change user language preference, this way interface language is always
-    // French no matter what path prefix the URLs have.
-    $edit = array('preferred_langcode' => 'fr');
-    $this->drupalPost("user/{$admin_user->uid}/edit", $edit, t('Save'));
-  }
-
-  /**
-   * Test that comment language is properly set.
-   */
-  function testCommentLanguage() {
-    drupal_static_reset('language_list');
-
-    // Create two nodes, one for english and one for french, and comment each
-    // node using both english and french as content language by changing URL
-    // language prefixes. Meanwhile interface language is always French, which
-    // is the user language preference. This way we can ensure that node
-    // language and interface language do not influence comment language, as
-    // only content language has to.
-    foreach (language_list() as $node_langcode => $node_language) {
-      $langcode_not_specified = LANGUAGE_NOT_SPECIFIED;
-
-      // Create "Article" content.
-      $title = $this->randomName();
-      $edit = array(
-        "title" => $title,
-        "body[$langcode_not_specified][0][value]" => $this->randomName(),
-        "langcode" => $node_langcode,
-      );
-      $this->drupalPost("node/add/article", $edit, t('Save'));
-      $node = $this->drupalGetNodeByTitle($title);
-
-      $prefixes = language_negotiation_url_prefixes();
-      foreach (language_list() as $langcode => $language) {
-        // Post a comment with content language $langcode.
-        $prefix = empty($prefixes[$langcode]) ? '' : $prefixes[$langcode] . '/';
-        $edit = array("comment_body[$langcode_not_specified][0][value]" => $this->randomName());
-        $this->drupalPost("{$prefix}node/{$node->nid}", $edit, t('Save'));
-
-        // Check that comment language matches the current content language.
-        $comment = db_select('comment', 'c')
-          ->fields('c')
-          ->condition('nid', $node->nid)
-          ->orderBy('cid', 'DESC')
-          ->execute()
-          ->fetchObject();
-        $args = array('%node_language' => $node_langcode, '%comment_language' => $comment->langcode, '%langcode' => $langcode);
-        $this->assertEqual($comment->langcode, $langcode, t('The comment posted with content language %langcode and belonging to the node with language %node_language has language %comment_language', $args));
-      }
-    }
-  }
-}
-
-/**
- * Functional tests for localizing date formats.
- */
-class LocaleDateFormatsFunctionalTest extends WebTestBase {
-
-  public static function getInfo() {
-    return array(
-      'name' => 'Localize date formats',
-      'description' => 'Tests for the localization of date formats.',
-      'group' => 'Locale',
-    );
-  }
-
-  function setUp() {
-    parent::setUp(array('node', 'locale'));
-
-    // Create Article node type.
-    $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
-
-    // Create and login user.
-    $admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer languages', 'access administration pages', 'create article content'));
-    $this->drupalLogin($admin_user);
-  }
-
-  /**
-   * Functional tests for localizing date formats.
-   */
-  function testLocalizeDateFormats() {
-    // Add language.
-    $edit = array(
-      'predefined_langcode' => 'fr',
-    );
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
-
-    // Set language negotiation.
-    $language_type = LANGUAGE_TYPE_INTERFACE;
-    $edit = array(
-      "{$language_type}[enabled][language-url]" => TRUE,
-    );
-    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
-
-    // Configure date formats.
-    $this->drupalGet('admin/config/regional/date-time/locale');
-    $this->assertText('French', 'Configured languages appear.');
-    $edit = array(
-      'date_format_long' => 'd.m.Y - H:i',
-      'date_format_medium' => 'd.m.Y - H:i',
-      'date_format_short' => 'd.m.Y - H:i',
-    );
-    $this->drupalPost('admin/config/regional/date-time/locale/fr/edit', $edit, t('Save configuration'));
-    $this->assertText(t('Configuration saved.'), 'French date formats updated.');
-    $edit = array(
-      'date_format_long' => 'j M Y - g:ia',
-      'date_format_medium' => 'j M Y - g:ia',
-      'date_format_short' => 'j M Y - g:ia',
-    );
-    $this->drupalPost('admin/config/regional/date-time/locale/en/edit', $edit, t('Save configuration'));
-    $this->assertText(t('Configuration saved.'), 'English date formats updated.');
-
-    // Create node content.
-    $node = $this->drupalCreateNode(array('type' => 'article'));
-
-    // Configure format for the node posted date changes with the language.
-    $this->drupalGet('node/' . $node->nid);
-    $english_date = format_date($node->created, 'custom', 'j M Y');
-    $this->assertText($english_date, t('English date format appears'));
-    $this->drupalGet('fr/node/' . $node->nid);
-    $french_date = format_date($node->created, 'custom', 'd.m.Y');
-    $this->assertText($french_date, t('French date format appears'));
-  }
-}
-- 
1.7.4.msysgit.0

