diff --git a/core/core.services.yml b/core/core.services.yml
index 2b27f69..a901073 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -863,6 +863,7 @@ services:
     arguments: ['@csrf_token']
   transliteration:
     class: Drupal\Core\Transliteration\PHPTransliteration
+    arguments: [null, '@module_handler']
   flood:
     class: Drupal\Core\Flood\DatabaseBackend
     arguments: ['@database', '@request_stack']
diff --git a/core/lib/Drupal/Core/Transliteration/PHPTransliteration.php b/core/lib/Drupal/Core/Transliteration/PHPTransliteration.php
index 675b20c..d8a3d15 100644
--- a/core/lib/Drupal/Core/Transliteration/PHPTransliteration.php
+++ b/core/lib/Drupal/Core/Transliteration/PHPTransliteration.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Transliteration;
 
 use Drupal\Component\Transliteration\PHPTransliteration as BaseTransliteration;
+use Drupal\Core\Extension\ModuleHandlerInterface;
 
 /**
  * Enhances PHPTransliteration with an alter hook.
@@ -18,6 +19,29 @@
 class PHPTransliteration extends BaseTransliteration {
 
   /**
+   * The module handler to execute the transliteration_overrides alter hook.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * Constructs a transliteration object.
+   *
+   * @param string $data_directory
+   *   (optional) The directory where data files reside. If omitted, defaults
+   *   to subdirectory 'data' underneath the directory where the class's PHP
+   *   file resides.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler to execute the transliteration_overrides alter hook.
+   */
+  public function __construct($data_directory = NULL, ModuleHandlerInterface $module_handler) {
+    parent::__construct($data_directory);
+
+    $this->moduleHandler = $module_handler;
+  }
+
+  /**
    * Overrides \Drupal\Component\Transliteration\PHPTransliteration::readLanguageOverrides().
    *
    * Allows modules to alter the language-specific $overrides array by invoking
@@ -27,7 +51,7 @@ protected function readLanguageOverrides($langcode) {
     parent::readLanguageOverrides($langcode);
 
     // Let modules alter the language-specific overrides.
-    \Drupal::moduleHandler()->alter('transliteration_overrides', $this->languageOverrides[$langcode], $langcode);
+    $this->moduleHandler->alter('transliteration_overrides', $this->languageOverrides[$langcode], $langcode);
   }
 
 }
diff --git a/core/modules/system/src/Tests/Transliteration/TransliterationTest.php b/core/modules/system/src/Tests/Transliteration/TransliterationTest.php
deleted file mode 100644
index 60a0e5c..0000000
--- a/core/modules/system/src/Tests/Transliteration/TransliterationTest.php
+++ /dev/null
@@ -1,112 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\system\Tests\Transliteration\TransliterationTest.
- */
-
-namespace Drupal\system\Tests\Transliteration;
-
-use Drupal\Core\Transliteration\PHPTransliteration;
-use Drupal\simpletest\KernelTestBase;
-
-/**
- * Tests Transliteration component functionality.
- *
- * @group Transliteration
- */
-class TransliterationTest extends KernelTestBase {
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('transliterate_test');
-
-  /**
-   * Tests the PHPTransliteration class.
-   */
-  public function testPHPTransliteration() {
-    $random = $this->randomMachineName(10);
-    // Make some strings with two, three, and four-byte characters for testing.
-    // Note that the 3-byte character is overridden by the 'kg' language.
-    $two_byte = 'Ä Ö Ü Å Ø äöüåøhello';
-    // This is a Cyrrillic character that looks something like a u. See
-    // http://www.unicode.org/charts/PDF/U0400.pdf
-    $three_byte = html_entity_decode('&#x446;', ENT_NOQUOTES, 'UTF-8');
-    // This is a Canadian Aboriginal character like a triangle. See
-    // http://www.unicode.org/charts/PDF/U1400.pdf
-    $four_byte = html_entity_decode('&#x1411;', ENT_NOQUOTES, 'UTF-8');
-    // These are two Gothic alphabet letters. See
-    // http://en.wikipedia.org/wiki/Gothic_alphabet
-    // They are not in our tables, but should at least give us '?' (unknown).
-    $five_byte = html_entity_decode('&#x10330;&#x10338;', ENT_NOQUOTES, 'UTF-8');
-    // Five-byte characters do not work in MySQL, so make a printable version.
-    $five_byte_printable = '&#x10330;&#x10338;';
-
-    $cases = array(
-      // Each test case is (language code, input, output).
-      // Test ASCII in English.
-      array('en', $random, $random),
-      // Test ASCII in some other language with no overrides.
-      array('fr', $random, $random),
-      // Test 3 and 4-byte characters in a language without overrides.
-      // Note: if the data tables change, these will need to change too! They
-      // are set up to test that data table loading works, so values come
-      // directly from the data files.
-      array('fr', $three_byte, 'c'),
-      array('fr', $four_byte, 'wii'),
-      // Test 5-byte characters.
-      array('en', $five_byte, '??', $five_byte_printable),
-      // Test a language with no overrides.
-      array('en', $two_byte, 'A O U A O aouaohello'),
-      // Test language overrides provided by core.
-      array('de', $two_byte, 'Ae Oe Ue A O aeoeueaohello'),
-      array('de', $random, $random),
-      array('dk', $two_byte, 'A O U Aa Oe aouaaoehello'),
-      array('dk', $random, $random),
-      array('kg', $three_byte, 'ts'),
-      // Test the language override hook in the test module, which changes
-      // the transliteration of Ä to Z and provides for the 5-byte characters.
-      array('zz', $two_byte, 'Z O U A O aouaohello'),
-      array('zz', $random, $random),
-      array('zz', $five_byte, 'ATh', $five_byte_printable),
-      // Test strings in some other languages.
-      // Turkish, provided by drupal.org user Kartagis.
-      array('tr', 'Abayı serdiler bize. Söyleyeceğim yüzlerine. Sanırım hepimiz aynı şeyi düşünüyoruz.', 'Abayi serdiler bize. Soyleyecegim yuzlerine. Sanirim hepimiz ayni seyi dusunuyoruz.'),
-    );
-
-    // Test each case both with a new instance of the transliteration class,
-    // and with one that builds as it goes.
-    $transliterator_service = $this->container->get('transliteration');
-
-    foreach($cases as $case) {
-      list($langcode, $original, $expected) = $case;
-      $printable = (isset($case[3])) ? $case[3] : $original;
-      $transliterator_class = new PHPTransliteration();
-      $actual = $transliterator_class->transliterate($original, $langcode);
-      $this->assertIdentical($actual, $expected, format_string('@original transliteration to @actual is identical to @expected for language @langcode in new class instance.', array(
-        '@original' => $printable,
-        '@langcode' => $langcode,
-        '@expected' => $expected,
-        '@actual' => $actual,
-      )));
-
-      $actual = $transliterator_service->transliterate($original, $langcode);
-      $this->assertIdentical($actual, $expected, format_string('@original transliteration to @actual is identical to @expected for language @langcode in service instance.', array(
-        '@original' => $printable,
-        '@langcode' => $langcode,
-        '@expected' => $expected,
-        '@actual' => $actual,
-      )));
-    }
-
-    // Test with max length, using German. It should never split up the
-    // transliteration of a single character.
-    $input = 'Ä Ö Ü Å Ø äöüåøhello';
-    $trunc_output = 'Ae Oe Ue A O aeoe';
-    $this->assertIdentical($trunc_output, $transliterator_service->transliterate($input, 'de', '?', 17), 'Truncating to 17 characters works');
-    $this->assertIdentical($trunc_output, $transliterator_service->transliterate($input, 'de', '?', 18), 'Truncating to 18 characters works');
-
-  }
-}
diff --git a/core/modules/system/tests/modules/transliterate_test/transliterate_test.info.yml b/core/modules/system/tests/modules/transliterate_test/transliterate_test.info.yml
deleted file mode 100644
index 9eeddd5..0000000
--- a/core/modules/system/tests/modules/transliterate_test/transliterate_test.info.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-name: 'Transliteration test'
-type: module
-description: 'Helper module for Transliteration system tests.'
-package: Testing
-version: VERSION
-core: 8.x
diff --git a/core/modules/system/tests/modules/transliterate_test/transliterate_test.module b/core/modules/system/tests/modules/transliterate_test/transliterate_test.module
deleted file mode 100644
index 636fde8..0000000
--- a/core/modules/system/tests/modules/transliterate_test/transliterate_test.module
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-
-/**
- * @file
- * Test module for Transliteration system.
- */
-
-/**
- * Implements hook_transliteration_overrides_alter().
- */
-function transliterate_test_transliteration_overrides_alter(&$overrides, $langcode) {
-  if ($langcode == 'zz') {
-    // The default transliteration of Ä is A, but change it to Z for testing.
-    $overrides[0xC4] = 'Z';
-    // Also provide transliterations of two 5-byte characters from
-    // http://en.wikipedia.org/wiki/Gothic_alphabet.
-    $overrides[0x10330] = 'A';
-    $overrides[0x10338] = 'Th';
-  }
-}
diff --git a/core/tests/Drupal/Tests/Component/Transliteration/PhpTransliterationTest.php b/core/tests/Drupal/Tests/Component/Transliteration/PhpTransliterationTest.php
new file mode 100644
index 0000000..0073743
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/Transliteration/PhpTransliterationTest.php
@@ -0,0 +1,119 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Component\Transliteration\PhpTransliterationTest.
+ */
+
+namespace Drupal\Tests\Component\Transliteration;
+
+use Drupal\Component\Transliteration\PHPTransliteration;
+use Drupal\Component\Utility\Random;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Tests Transliteration component functionality.
+ *
+ * @group Transliteration
+ *
+ * @coversClass \Drupal\Component\Transliteration\PhpTransliteration
+ */
+class PhpTransliterationTest extends UnitTestCase {
+
+  /**
+   * Tests the PHPTransliteration class.
+   *
+   * @param string $langcode
+   *   The language code to test.
+   * @param string $original
+   *   The original string.
+   * @param string $expected
+   *   The expected return from PHPTransliteration::transliterate().
+   * @param string $unknown_character
+   *   (optional) The character to substitute for characters in $string without
+   *   transliterated equivalents. Defaults to '?'.
+   * @param int $max_length
+   *   (optional) If provided, return at most this many characters, ensuring
+   *   that the transliteration does not split in the middle of an input
+   *   character's transliteration.
+   *
+   * @dataProvider providerTestPhpTransliteration
+   */
+  public function testPhpTransliteration($langcode, $original, $expected, $unknown_character = '?', $max_length = NULL) {
+    $transliterator_class = new PHPTransliteration();
+    $actual = $transliterator_class->transliterate($original, $langcode, $unknown_character, $max_length);
+    $this->assertSame($expected, $actual);
+  }
+
+  /**
+   * Provides data for self::testPhpTransliteration().
+   *
+   * @return array
+   *   An array of arrays, each containing the parameters for
+   *   self::testPhpTransliteration().
+   */
+  public function providerTestPhpTransliteration() {
+    $random_generator = new Random();
+    $random = $random_generator->string(10);
+    // Make some strings with two, three, and four-byte characters for testing.
+    // Note that the 3-byte character is overridden by the 'kg' language.
+    $two_byte = 'Ä Ö Ü Å Ø äöüåøhello';
+    // This is a Cyrrillic character that looks something like a u. See
+    // http://www.unicode.org/charts/PDF/U0400.pdf
+    $three_byte = html_entity_decode('&#x446;', ENT_NOQUOTES, 'UTF-8');
+    // This is a Canadian Aboriginal character like a triangle. See
+    // http://www.unicode.org/charts/PDF/U1400.pdf
+    $four_byte = html_entity_decode('&#x1411;', ENT_NOQUOTES, 'UTF-8');
+    // These are two Gothic alphabet letters. See
+    // http://en.wikipedia.org/wiki/Gothic_alphabet
+    // They are not in our tables, but should at least give us '?' (unknown).
+    $five_byte = html_entity_decode('&#x10330;&#x10338;', ENT_NOQUOTES, 'UTF-8');
+
+    return array(
+      // Each test case is (language code, input, output).
+      // Test ASCII in English.
+      array('en', $random, $random),
+      // Test ASCII in some other language with no overrides.
+      array('fr', $random, $random),
+      // Test 3 and 4-byte characters in a language without overrides.
+      // Note: if the data tables change, these will need to change too! They
+      // are set up to test that data table loading works, so values come
+      // directly from the data files.
+      array('fr', $three_byte, 'c'),
+      array('fr', $four_byte, 'wii'),
+      // Test 5-byte characters.
+      array('en', $five_byte, '??'),
+      // Test a language with no overrides.
+      array('en', $two_byte, 'A O U A O aouaohello'),
+      // Test language overrides provided by core.
+      array('de', $two_byte, 'Ae Oe Ue A O aeoeueaohello'),
+      array('de', $random, $random),
+      array('dk', $two_byte, 'A O U Aa Oe aouaaoehello'),
+      array('dk', $random, $random),
+      array('kg', $three_byte, 'ts'),
+      // Test strings in some other languages.
+      // Turkish, provided by drupal.org user Kartagis.
+      array('tr', 'Abayı serdiler bize. Söyleyeceğim yüzlerine. Sanırım hepimiz aynı şeyi düşünüyoruz.', 'Abayi serdiler bize. Soyleyecegim yuzlerine. Sanirim hepimiz ayni seyi dusunuyoruz.'),
+      // Illegal/unknown unicode.
+      array('en', chr(0xF8) . chr(0x80) . chr(0x80) . chr(0x80) . chr(0x80), '?'),
+      // Max length.
+      array('de', $two_byte, 'Ae Oe', '?', 5),
+    );
+  }
+
+  /**
+   * Tests the transliteration with max length.
+   */
+  public function testTransliterationWithMaxLength() {
+    $transliteration = new PHPTransliteration();
+
+    // Test with max length, using German. It should never split up the
+    // transliteration of a single character.
+    $input = 'Ä Ö Ü Å Ø äöüåøhello';
+    $trunc_output = 'Ae Oe Ue A O aeoe';
+
+    $this->assertSame($trunc_output, $transliteration->transliterate($input, 'de', '?', 17), 'Truncating to 17 characters works');
+    $this->assertSame($trunc_output, $transliteration->transliterate($input, 'de', '?', 18), 'Truncating to 18 characters works');
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Block/BlockBaseTest.php b/core/tests/Drupal/Tests/Core/Block/BlockBaseTest.php
index 88be050..4c64bf2 100644
--- a/core/tests/Drupal/Tests/Core/Block/BlockBaseTest.php
+++ b/core/tests/Drupal/Tests/Core/Block/BlockBaseTest.php
@@ -22,8 +22,9 @@ class BlockBaseTest extends UnitTestCase {
    * @see \Drupal\Core\Block\BlockBase::getMachineNameSuggestion().
    */
   public function testGetMachineNameSuggestion() {
+    $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
     $transliteration = $this->getMockBuilder('Drupal\Core\Transliteration\PHPTransliteration')
-      // @todo Inject the module handler into PHPTransliteration.
+      ->setConstructorArgs(array(NULL, $module_handler))
       ->setMethods(array('readLanguageOverrides'))
       ->getMock();
 
diff --git a/core/tests/Drupal/Tests/Core/Transliteration/PhpTransliterationTest.php b/core/tests/Drupal/Tests/Core/Transliteration/PhpTransliterationTest.php
new file mode 100644
index 0000000..00cb566
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Transliteration/PhpTransliterationTest.php
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Transliteration\PhpTransliterationTest.
+ */
+
+namespace Drupal\Tests\Core\Transliteration;
+
+use Drupal\Component\Utility\Random;
+use Drupal\Component\Utility\String;
+use Drupal\Core\Transliteration\PHPTransliteration;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * Tests Transliteration component functionality.
+ *
+ * @group Transliteration
+ *
+ * @coversClass \Drupal\Core\Transliteration\PhpTransliteration
+ */
+class PhpTransliterationTest extends UnitTestCase {
+
+  /**
+   * Tests the PHPTransliteration with an alter hook.
+   *
+   * @param string $langcode
+   *   The langcode of the string.
+   * @param string $original
+   *   The string which was not transliterated yet.
+   * @param string $expected
+   *   The string expected after the transliteration.
+   * @param string|NULL $printable
+   *   (optional) An alternative version of the original string which is
+   *   printable in the output.
+   *
+   * @dataProvider providerTestPhpTransliterationWithAlter
+   */
+  public function testPhpTransliterationWithAlter($langcode, $original, $expected, $printable = NULL) {
+    if ($printable === NULL) {
+      $printable = $original;
+    }
+
+    // Test each case both with a new instance of the transliteration class,
+    // and with one that builds as it goes.
+    $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
+    $module_handler->expects($this->any())
+      ->method('alter')
+      ->will($this->returnCallback(function($hook, &$overrides, $langcode) {
+        if ($langcode == 'zz') {
+          // The default transliteration of Ä is A, but change it to Z for testing.
+          $overrides[0xC4] = 'Z';
+          // Also provide transliterations of two 5-byte characters from
+          // http://en.wikipedia.org/wiki/Gothic_alphabet.
+          $overrides[0x10330] = 'A';
+          $overrides[0x10338] = 'Th';
+        }
+      }));
+    $transliteration = new PHPTransliteration(NULL, $module_handler);
+
+    $actual = $transliteration->transliterate($original, $langcode);
+    $this->assertSame($expected, $actual, String::format('@original transliteration to @actual is identical to @expected for language @langcode in service instance.', array(
+      '@original' => $printable,
+      '@langcode' => $langcode,
+      '@expected' => $expected,
+      '@actual' => $actual,
+    )));
+  }
+
+  /**
+   * Provides test data for testPhpTransliterationWithAlter.
+   *
+   * @return array
+   */
+  public function providerTestPhpTransliterationWithAlter() {
+    $random_generator = new Random();
+    $random = $random_generator->string(10);
+    // Make some strings with two, three, and four-byte characters for testing.
+    // Note that the 3-byte character is overridden by the 'kg' language.
+    $two_byte = 'Ä Ö Ü Å Ø äöüåøhello';
+    // These are two Gothic alphabet letters. See
+    // http://en.wikipedia.org/wiki/Gothic_alphabet
+    // They are not in our tables, but should at least give us '?' (unknown).
+    $five_byte = html_entity_decode('&#x10330;&#x10338;', ENT_NOQUOTES, 'UTF-8');
+    // Five-byte characters do not work in MySQL, so make a printable version.
+    $five_byte_printable = '&#x10330;&#x10338;';
+
+    $cases = array(
+      // Test the language override hook in the test module, which changes
+      // the transliteration of Ä to Z and provides for the 5-byte characters.
+      array('zz', $two_byte, 'Z O U A O aouaohello'),
+      array('zz', $random, $random),
+      array('zz', $five_byte, 'ATh', $five_byte_printable),
+    );
+
+    return $cases;
+  }
+
+}
