diff --git a/core/core.services.yml b/core/core.services.yml index 9a36139..1693633 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -167,6 +167,12 @@ services: arguments: ['@event_dispatcher', '@service_container', '@controller_resolver'] language_manager: class: Drupal\Core\Language\LanguageManager + string_translator.custom_strings: + class: Drupal\Core\StringTranslation\Translator\CustomStrings + tags: + - { name: string_translator, priority: 30 } + string_translation: + class: Drupal\Core\StringTranslation\TranslationManager database.slave: class: Drupal\Core\Database\Connection factory_class: Drupal\Core\Database\Database @@ -369,7 +375,7 @@ services: class: Drupal\Core\EventSubscriber\LanguageRequestSubscriber tags: - { name: event_subscriber } - arguments: ['@language_manager'] + arguments: ['@language_manager', '@string_translation'] exception_controller: class: Drupal\Core\Controller\ExceptionController arguments: ['@content_negotiation'] diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 7dc75f5..c225b1b 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -1461,37 +1461,7 @@ function bootstrap_hooks() { * @ingroup sanitization */ function t($string, array $args = array(), array $options = array()) { - static $custom_strings; - - // Merge in default. - if (empty($options['langcode'])) { - $options['langcode'] = language(LANGUAGE_TYPE_INTERFACE)->langcode; - } - if (empty($options['context'])) { - $options['context'] = ''; - } - - // First, check for an array of customized strings. If present, use the array - // *instead of* database lookups. This is a high performance way to provide a - // handful of string replacements. See settings.php for examples. - // Cache the $custom_strings variable to improve performance. - if (!isset($custom_strings[$options['langcode']])) { - $custom_strings[$options['langcode']] = variable_get('locale_custom_strings_' . $options['langcode'], array()); - } - // Custom strings work for English too, even if locale module is disabled. - if (isset($custom_strings[$options['langcode']][$options['context']][$string])) { - $string = $custom_strings[$options['langcode']][$options['context']][$string]; - } - // Translate with locale module if enabled. - elseif ($options['langcode'] != LANGUAGE_SYSTEM && ($options['langcode'] != 'en' || variable_get('locale_translate_english', FALSE)) && function_exists('locale')) { - $string = locale($string, $options['context'], $options['langcode']); - } - if (empty($args)) { - return $string; - } - else { - return format_string($string, $args); - } + return Drupal::translation()->translate($string, $args, $options); } /** @@ -2542,27 +2512,23 @@ function drupal_installation_attempted() { * Use st() if your code will only run during installation and never any other * time. Use get_t() if your code could run in either circumstance. * + * @todo Remove this in favor of t(). + * * @see t() * @see st() * @ingroup sanitization */ function get_t() { - static $t; - // This is not converted to drupal_static because there is no point in - // resetting this as it can not change in the course of a request. - if (!isset($t)) { - $t = drupal_installation_attempted() ? 'st' : 't'; - } - return $t; + return 't'; } /** - * Initializes all the defined language types. - * - * @see language() + * Initializes all the defined language types and sets the default langcode. */ function drupal_language_initialize() { - drupal_container()->get('language_manager')->init(); + $language_manager = Drupal::service('language_manager'); + $language_manager->init(); + Drupal::translation()->setDefaultLangcode($language_manager->getLanguage(LANGUAGE_TYPE_INTERFACE)->langcode); } /** @@ -2572,19 +2538,12 @@ function drupal_language_initialize() { * * @param string $type * The type of language object needed, e.g. LANGUAGE_TYPE_INTERFACE. + * + * @deprecated as of Drupal 8.0. Use + * Drupal::service('language_manager')->getLanguage($type). */ function language($type) { - $container = drupal_container(); - if (!$container) { - return language_default(); - } - if (!$container->has('language_manager')) { - // This happens in rare situations when the container has not been built by - // a kernel and has no services, e.g., when t() is called during unit tests - // for assertions. - $container->register('language_manager', 'Drupal\Core\Language\LanguageManager'); - } - return $container->get('language_manager')->getLanguage($type); + return Drupal::service('language_manager')->getLanguage($type); } /** diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 32c0b49..d009c5d 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -8,6 +8,7 @@ use Drupal\Core\Database\Database; use Drupal\Core\Database\Install\TaskException; use Drupal\Core\Language\Language; +use Drupal\Core\StringTranslation\Translator\FileTranslation; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; @@ -366,6 +367,12 @@ function install_begin_request(&$install_state) { // Register the 'language_manager' service. $container->register('language_manager', 'Drupal\Core\Language\LanguageManager'); + + // Register the translation services. + $container->register('string_translator.custom_strings', 'Drupal\Core\StringTranslation\Translator\CustomStrings') + ->addTag('string_translator'); + $container->register('string_translation', 'Drupal\Core\StringTranslation\TranslationManager'); + foreach (array('bootstrap', 'config', 'cache', 'menu', 'page', 'path') as $bin) { $container ->register("cache.$bin", 'Drupal\Core\Cache\MemoryBackend') @@ -411,6 +418,12 @@ function install_begin_request(&$install_state) { // Set up $language, so t() caller functions will still work. drupal_language_initialize(); + // Append file translation to the translation chain. + Drupal::translation()->addTranslator(install_file_translation_service()); + // Add in installation language if present. + if (isset($install_state['parameters']['langcode'])) { + Drupal::translation()->setDefaultLangcode($install_state['parameters']['langcode']); + } require_once __DIR__ . '/ajax.inc'; @@ -1337,7 +1350,7 @@ function install_select_profile_form($form, &$form_state, $install_state) { */ function install_find_translations() { $translations = array(); - $files = install_find_translation_files(); + $files = install_file_translation_service()->findTranslationFiles(); // English does not need a translation file. array_unshift($files, (object) array('name' => 'en')); foreach ($files as $uri => $file) { @@ -1353,37 +1366,24 @@ function install_find_translations() { } /** - * Finds installer translations either for a specific langcode or all languages. + * Build a file translation service for installation. * - * @param $langcode - * (optional) The language code corresponding to the language for which we - * want to find translation files. If omitted, information on all available - * files will be returned. - * - * @return - * An associative array of file information objects keyed by file URIs as - * returned by file_scan_directory(). - * - * @see file_scan_directory() + * @return Drupal\Core\StringTranslation\Translator\FileTranslation + * File translation service for the installer. */ -function install_find_translation_files($langcode = NULL) { - return file_scan_directory(install_translation_directory(), '!drupal-\d+\.\d+\.' . (!empty($langcode) ? preg_quote($langcode, '!') : '[^\.]+') . '\.po$!', array('recurse' => FALSE)); -} +function install_file_translation_service() { + static $translation; -/** - * Get installation translations directory path. - * - * @return string - * A string containing the installation translations directory path. - */ -function install_translation_directory() { - if (isset($GLOBALS['conf']['locale.settings']['translation.path'])) { - $directory = $GLOBALS['conf']['locale.settings']['translation.path']; - } - else { - $directory = conf_path() . '/files/translations'; + if (!isset($translation)) { + if (isset($GLOBALS['conf']['locale.settings']['translation.path'])) { + $directory = $GLOBALS['conf']['locale.settings']['translation.path']; + } + else { + $directory = conf_path() . '/files/translations'; + } + $translation = new FileTranslation($directory); } - return $directory; + return $translation; } /** diff --git a/core/includes/install.inc b/core/includes/install.inc index 84dd851..0921106 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -8,7 +8,8 @@ use Drupal\Component\Utility\Crypt; use Drupal\Core\Database\Database; use Drupal\Core\DrupalKernel; -use Drupal\locale\Gettext; +use Drupal\Core\StringTranslation\TranslationManager; +use Drupal\Core\StringTranslation\Translator\CustomStrings; /** * Requirement severity -- Informational message only. @@ -944,48 +945,28 @@ function drupal_requirements_url($severity) { * @ingroup sanitization */ function st($string, array $args = array(), array $options = array()) { - static $strings = NULL; global $install_state; + static $install_translation; - if (empty($options['context'])) { - $options['context'] = ''; + // This may be invoked before the container has been initialized. + $container = Drupal::getContainer(); + if ($container && $container->has('translation')) { + // Since the container is properly initialized, we can use standard translation. + return t($string, $args, $options); } - - if (!isset($strings)) { - $strings = array(); - if (isset($install_state['parameters']['langcode'])) { - // If the given langcode was selected, there should be at least one .po - // file with its name in the pattern drupal-$version.$langcode.po. - // This might or might not be the entire filename. It is also possible - // that multiple files end with the same suffix, even if unlikely. - $files = install_find_translation_files($install_state['parameters']['langcode']); - if (!empty($files)) { - // Register locale classes with the classloader. Locale module is not - // yet enabled at this stage, so this is not happening automatically. - drupal_classloader_register('locale', drupal_get_path('module', 'locale')); - $strings = Gettext::filesToArray($install_state['parameters']['langcode'], $files); + elseif (drupal_installation_attempted() && isset($install_state['parameters']['langcode'])) { + // The translation service is not there yet, use a temporary one. + if (!isset($install_translation)) { + $install_translation = new TranslationManager(); + foreach (array(new CustomStrings(), install_file_translation_service()) as $translator) { + $install_translation->addTranslator($translator); } + $install_translation->setDefaultLangcode($install_state['parameters']['langcode']); } + return $install_translation->translate($string, $args, $options); } - - require_once __DIR__ . '/theme.inc'; - // Transform arguments before inserting them - foreach ($args as $key => $value) { - switch ($key[0]) { - // Escaped only - case '@': - $args[$key] = check_plain($value); - break; - // Escaped and placeholder - case '%': - default: - $args[$key] = '' . check_plain($value) . ''; - break; - // Pass-through - case '!': - } - } - return strtr((!empty($strings[$options['context']][$string]) ? $strings[$options['context']][$string] : $string), $args); + // Just return an untraslated string. + return format_string($string, $args); } /** diff --git a/core/includes/update.inc b/core/includes/update.inc index a5feb50..9ddb96b 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -388,7 +388,6 @@ function update_prepare_d8_bootstrap() { $disabled_modules->save(); $theme_config->save(); $disabled_themes->save(); - Drupal::service('kernel')->updateModules($sorted_with_filenames, $sorted_with_filenames); // Migrate the private key to state. This is used to create the token for // the upgrade batch so needs to be be done before the upgrade has begun. @@ -401,6 +400,9 @@ function update_prepare_d8_bootstrap() { update_prepare_stored_includes(); // Update the environment for the language bootstrap if needed. update_prepare_d8_language(); + // Rebuild kernel after new language fields are added in the database + // because the translation service depends on them being there. + Drupal::service('kernel')->updateModules($sorted_with_filenames, $sorted_with_filenames); // Change language column to langcode in url_alias. if (db_table_exists('url_alias') && db_field_exists('url_alias', 'language')) { diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php index d8a68ba..3587e8b 100644 --- a/core/lib/Drupal.php +++ b/core/lib/Drupal.php @@ -361,4 +361,14 @@ public static function token() { return static::$container->get('token'); } + /** + * Returns the string translation service. + * + * @return \Drupal\Core\Translation\TranslationManager + * The string translation manager. + */ + public static function translation() { + return static::$container->get('string_translation'); + } + } diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php index 2d85f6a..2faebd9 100644 --- a/core/lib/Drupal/Core/CoreBundle.php +++ b/core/lib/Drupal/Core/CoreBundle.php @@ -16,6 +16,7 @@ use Drupal\Core\DependencyInjection\Compiler\RegisterRouteEnhancersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterParamConvertersPass; use Drupal\Core\DependencyInjection\Compiler\RegisterServicesForDestructionPass; +use Drupal\Core\DependencyInjection\Compiler\RegisterStringTranslatorsPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Reference; @@ -60,6 +61,8 @@ public function build(ContainerBuilder $container) { // Add the compiler pass that will process the tagged services. $container->addCompilerPass(new RegisterPathProcessorsPass()); $container->addCompilerPass(new ListCacheBinsPass()); + // Add the compiler pass for appending string translators. + $container->addCompilerPass(new RegisterStringTranslatorsPass()); } /** diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterStringTranslatorsPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterStringTranslatorsPass.php new file mode 100644 index 0000000..39a0764 --- /dev/null +++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterStringTranslatorsPass.php @@ -0,0 +1,33 @@ +hasDefinition('string_translation')) { + return; + } + $access_manager = $container->getDefinition('string_translation'); + foreach ($container->findTaggedServiceIds('string_translator') as $id => $attributes) { + $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; + $access_manager->addMethodCall('addTranslator', array(new Reference($id), $priority)); + } + } + +} diff --git a/core/lib/Drupal/Core/EventSubscriber/LanguageRequestSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/LanguageRequestSubscriber.php index cc181ac..5e80dd5 100644 --- a/core/lib/Drupal/Core/EventSubscriber/LanguageRequestSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/LanguageRequestSubscriber.php @@ -8,6 +8,7 @@ namespace Drupal\Core\EventSubscriber; use Drupal\Core\Language\LanguageManager; +use Drupal\Core\StringTranslation\Translator\TranslatorInterface; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Event\GetResponseEvent; @@ -26,14 +27,24 @@ class LanguageRequestSubscriber implements EventSubscriberInterface { protected $languageManager; /** + * The translation service. + * + * @var \Drupal\Core\Translation\Translator\TranslatorInterface + */ + protected $translation; + + /** * Constructs a LanguageRequestSubscriber object. * * @param \Drupal\Core\Language\LanguageManager $language_manager * The language manager service. * + * @param \Drupal\Core\Translation\Translator\TranslatorInterface $translation + * The translation service. */ - public function __construct(LanguageManager $language_manager) { + public function __construct(LanguageManager $language_manager, TranslatorInterface $translation) { $this->languageManager = $language_manager; + $this->translation = $translation; } /** @@ -45,6 +56,10 @@ public function __construct(LanguageManager $language_manager) { public function onKernelRequestLanguage(GetResponseEvent $event) { if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) { $this->languageManager->setRequest($event->getRequest()); + // After the language manager has initialized, set the default langcode + // for the string translations. + $langcode = $this->languageManager->getLanguage(LANGUAGE_TYPE_INTERFACE)->langcode; + $this->translation->setDefaultLangcode($langcode); } } diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php new file mode 100644 index 0000000..b465983 --- /dev/null +++ b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php @@ -0,0 +1,148 @@ +defaultLangcode = language_default()->langcode; + } + + /** + * Appends a translation system to the translation chain. + * + * @param \Drupal\Core\Translation\Translator\TranslatorInterface $translator + * The translation interface to be appended to the translation chain. + * @param int $priority + * The priority of the logger being added. + * + * @return \Drupal\Core\Translation\TranslationManager + * The called object. + */ + public function addTranslator(TranslatorInterface $translator, $priority = 0) { + $this->translators[$priority][] = $translator; + + return $this; + } + + /** + * Sorts translators according to priority. + * + * @return array + * A sorted array of translators objects. + */ + protected function sortTranslators() { + $sorted = array(); + krsort($this->translators); + + foreach ($this->translators as $translators) { + $sorted = array_merge($sorted, $translators); + } + return $sorted; + } + + /** + * {@inheritdoc} + */ + public function getStringTranslation($langcode, $string, $context) { + foreach ($this->sortTranslators() as $translator) { + $translation = $translator->getStringTranslation($langcode, $string, $context); + if ($translation !== FALSE) { + return $translation; + } + } + // No translator got a translation. + return FALSE; + } + + /** + * Translates a string to the current language or to a given language. + * + * @param string $string + * A string containing the English string to translate. + * @param array $args + * An associative array of replacements to make after translation. Based + * on the first character of the key, the value is escaped and/or themed. + * See \Drupal\Core\Utility\String::format() for details. + * @param array $options + * An associative array of additional options, with the following elements: + * - 'langcode': The language code to translate to a language other than + * what is used to display the page. + * - 'context': The context the source string belongs to. + * + * @return string + * The translated string. + * + * @see t() + * @see \Drupal\Core\Utility\String::format() + */ + public function translate($string, array $args = array(), array $options = array()) { + // Merge in defaults. + if (empty($options['langcode'])) { + $options['langcode'] = $this->defaultLangcode; + } + if (empty($options['context'])) { + $options['context'] = ''; + } + $translation = $this->getStringTranslation($options['langcode'], $string, $options['context']); + $string = $translation === FALSE ? $string : $translation; + + if (empty($args)) { + return $string; + } + else { + return String::format($string, $args); + } + } + + /** + * Sets the default langcode. + * + * @param string $langcode + * A language code. + */ + public function setDefaultLangcode($langcode) { + $this->defaultLangcode = $langcode; + } + + /** + * {@inheritdoc} + */ + public function reset() { + foreach ($this->sortTranslators() as $translator) { + $translator->reset(); + } + } + +} diff --git a/core/lib/Drupal/Core/StringTranslation/Translator/CustomStrings.php b/core/lib/Drupal/Core/StringTranslation/Translator/CustomStrings.php new file mode 100644 index 0000000..a1ed337 --- /dev/null +++ b/core/lib/Drupal/Core/StringTranslation/Translator/CustomStrings.php @@ -0,0 +1,25 @@ +directory = $directory; + } + + /** + * {@inheritdoc} + */ + protected function loadLanguage($langcode) { + // If the given langcode was selected, there should be at least one .po + // file with its name in the pattern drupal-$version.$langcode.po. + // This might or might not be the entire filename. It is also possible + // that multiple files end with the same suffix, even if unlikely. + $files = $this->findTranslationFiles($langcode); + + if (!empty($files)) { + return $this->filesToArray($langcode, $files); + } + else { + return array(); + } + } + + /** + * Finds installer translations either for a specific langcode or all languages. + * + * @param string $langcode + * (optional) The language code corresponding to the language for which we + * want to find translation files. If omitted, information on all available + * files will be returned. + * + * @return array + * An associative array of file information objects keyed by file URIs as + * returned by file_scan_directory(). + * + * @see file_scan_directory() + */ + public function findTranslationFiles($langcode = NULL) { + $files = file_scan_directory($this->directory, '!drupal-\d+\.\d+\.' . (!empty($langcode) ? preg_quote($langcode, '!') : '[^\.]+') . '\.po$!', array('recurse' => FALSE)); + return $files; + } + + /** + * Reads the given Gettext PO files into a data structure. + * + * @param string $langcode + * Language code string. + * @param array $files + * List of file objects with URI properties pointing to read. + * + * @return array + * Structured array as produced by a PoMemoryWriter. + * + * @see \Drupal\Component\Gettext\PoMemoryWriter + */ + public static function filesToArray($langcode, array $files) { + $writer = new PoMemoryWriter(); + $writer->setLangcode($langcode); + foreach ($files as $file) { + $reader = new PoStreamReader(); + $reader->setURI($file->uri); + $reader->setLangcode($langcode); + $reader->open(); + $writer->writeItems($reader, -1); + } + return $writer->getData(); + } +} diff --git a/core/lib/Drupal/Core/StringTranslation/Translator/StaticTranslation.php b/core/lib/Drupal/Core/StringTranslation/Translator/StaticTranslation.php new file mode 100644 index 0000000..538b1df --- /dev/null +++ b/core/lib/Drupal/Core/StringTranslation/Translator/StaticTranslation.php @@ -0,0 +1,67 @@ +translations = $translations; + } + + /** + * {@inheritdoc} + */ + public function getStringTranslation($langcode, $string, $context) { + if (!isset($this->translations[$langcode])) { + $this->translations[$langcode] = $this->loadLanguage($langcode); + } + if (isset($this->translations[$langcode][$context][$string])) { + return $this->translations[$langcode][$context][$string]; + } + else { + return FALSE; + } + } + + /** + * {@inheritdoc} + */ + public function reset() { + $this->translations = array(); + } + + /** + * Add translations for new language. + * + * @param string $langcode + * The langcode of the language. + */ + protected function loadLanguage($langcode) { + return array(); + } + +} diff --git a/core/lib/Drupal/Core/StringTranslation/Translator/TranslatorInterface.php b/core/lib/Drupal/Core/StringTranslation/Translator/TranslatorInterface.php new file mode 100644 index 0000000..550b68e --- /dev/null +++ b/core/lib/Drupal/Core/StringTranslation/Translator/TranslatorInterface.php @@ -0,0 +1,38 @@ +setLangcode($langcode); - foreach ($files as $file) { - $reader = new PoStreamReader(); - $reader->setURI($file->uri); - $reader->setLangcode($langcode); - $reader->open(); - $writer->writeItems($reader, -1); - } - return $writer->getData(); - } - - /** * Reads the given PO files into the database. * * @param stdClass $file diff --git a/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php b/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php index 5b0db2d..8cba49a 100644 --- a/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php +++ b/core/modules/locale/lib/Drupal/locale/LocaleConfigManager.php @@ -46,14 +46,13 @@ class LocaleConfigManager extends TypedConfigManager { * The storage controller object to use for reading default configuration * data. * @param \Drupal\locale\StringStorageInterface $localeStorage - * (optional) The locale storage to use for reading string translations. - * Defaults to locale_storage(). + * The locale storage to use for reading string translations. */ - public function __construct(StorageInterface $configStorage, StorageInterface $schemaStorage, StorageInterface $installStorage, StringStorageInterface $localeStorage = NULL) { + public function __construct(StorageInterface $configStorage, StorageInterface $schemaStorage, StorageInterface $installStorage, StringStorageInterface $localeStorage) { // Note we use the install storage for the parent constructor. parent::__construct($configStorage, $schemaStorage); $this->installStorage = $installStorage; - $this->localeStorage = $localeStorage ?: locale_storage(); + $this->localeStorage = $localeStorage; } /** diff --git a/core/modules/locale/lib/Drupal/locale/LocaleLookup.php b/core/modules/locale/lib/Drupal/locale/LocaleLookup.php index cc515b4..d4530cf 100644 --- a/core/modules/locale/lib/Drupal/locale/LocaleLookup.php +++ b/core/modules/locale/lib/Drupal/locale/LocaleLookup.php @@ -2,7 +2,7 @@ /** * @file - * Definition of LocaleLookup + * Contains \Drupal\locale\Locale\Lookup. */ namespace Drupal\locale; @@ -18,46 +18,48 @@ class LocaleLookup extends CacheArray { /** * A language code. + * * @var string */ protected $langcode; /** * The msgctxt context. + * * @var string */ protected $context; /** - * The locale storage + * The locale storage. * - * @var Drupal\locale\StringStorageInterface + * @var \Drupal\locale\StringStorageInterface */ protected $stringStorage; /** - * Constructs a LocaleCache object. + * Constructs a \Drupal\locale\Locale\Lookup object. */ - public function __construct($langcode, $context, $stringStorage) { + public function __construct($langcode, $context, $string_storage) { $this->langcode = $langcode; $this->context = (string) $context; - $this->stringStorage = $stringStorage; + $this->stringStorage = $string_storage; // Add the current user's role IDs to the cache key, this ensures that, for // example, strings for admin menu items and settings forms are not cached // for anonymous users. - $rids = implode(':', array_keys($GLOBALS['user']->roles)); + $rids = isset($GLOBALS['user']) ? implode(':', array_keys($GLOBALS['user']->roles)) : '0'; parent::__construct("locale:$langcode:$context:$rids", 'cache', array('locale' => TRUE)); } /** - * Implements CacheArray::resolveCacheMiss(). + * {@inheritdoc} */ protected function resolveCacheMiss($offset) { $translation = $this->stringStorage->findTranslation(array( 'language' => $this->langcode, 'source' => $offset, - 'context' => $this->context + 'context' => $this->context, )); if ($translation) { @@ -83,4 +85,13 @@ protected function resolveCacheMiss($offset) { } return $value; } + + /** + * {@inheritdoc} + */ + public function __destruct() { + // Do nothing to avoid segmentation faults. This can be restored after the + // cache collector from http://drupal.org/node/1786490 is used. + } + } diff --git a/core/modules/locale/lib/Drupal/locale/LocaleTranslation.php b/core/modules/locale/lib/Drupal/locale/LocaleTranslation.php new file mode 100644 index 0000000..b10c7b8 --- /dev/null +++ b/core/modules/locale/lib/Drupal/locale/LocaleTranslation.php @@ -0,0 +1,72 @@ +storage = $storage; + } + + /** + * {@inheritdoc} + */ + public function getStringTranslation($langcode, $string, $context) { + // If the language is not suitable for locale module, just return. + if ($langcode == LANGUAGE_SYSTEM || ($langcode == 'en' && !locale_translate_english())) { + return FALSE; + } + // Strings are cached by langcode, context and roles, using instances of the + // LocaleLookup class to handle string lookup and caching. + if (!isset($this->translations[$langcode][$context])) { + $this->translations[$langcode][$context] = new LocaleLookup($langcode, $context, $this->storage); + } + $translation = $this->translations[$langcode][$context][$string]; + return $translation === TRUE ? FALSE : $translation; + } + + /** + * {@inheritdoc} + */ + public function reset() { + $this->translations = array(); + } + +} diff --git a/core/modules/locale/lib/Drupal/locale/PoDatabaseReader.php b/core/modules/locale/lib/Drupal/locale/PoDatabaseReader.php index f2660fd..019ce95 100644 --- a/core/modules/locale/lib/Drupal/locale/PoDatabaseReader.php +++ b/core/modules/locale/lib/Drupal/locale/PoDatabaseReader.php @@ -145,11 +145,11 @@ private function loadStrings() { // Filter for string with translation. $conditions['translated'] = TRUE; } - return locale_storage()->getTranslations($conditions); + return \Drupal::service('locale.storage')->getTranslations($conditions); } else { // If no language, we don't need any of the target fields. - return locale_storage()->getStrings($conditions); + return \Drupal::service('locale.storage')->getStrings($conditions); } } diff --git a/core/modules/locale/lib/Drupal/locale/PoDatabaseWriter.php b/core/modules/locale/lib/Drupal/locale/PoDatabaseWriter.php index 126ee04..f4a3283 100644 --- a/core/modules/locale/lib/Drupal/locale/PoDatabaseWriter.php +++ b/core/modules/locale/lib/Drupal/locale/PoDatabaseWriter.php @@ -229,7 +229,7 @@ private function importString(PoItem $item) { $translation = $item->getTranslation(); // Look up the source string and any existing translation. - $strings = locale_storage()->getTranslations(array( + $strings = \Drupal::service('locale.storage')->getTranslations(array( 'language' => $this->_langcode, 'source' => $source, 'context' => $context @@ -265,9 +265,9 @@ private function importString(PoItem $item) { } else { // No such source string in the database yet. - $string = locale_storage()->createString(array('source' => $source, 'context' => $context)) + $string = \Drupal::service('locale.storage')->createString(array('source' => $source, 'context' => $context)) ->save(); - $target = locale_storage()->createTranslation(array( + $target = \Drupal::service('locale.storage')->createTranslation(array( 'lid' => $string->getId(), 'language' => $this->_langcode, 'translation' => $translation, diff --git a/core/modules/locale/lib/Drupal/locale/StringDatabaseStorage.php b/core/modules/locale/lib/Drupal/locale/StringDatabaseStorage.php index bb1b28b..d18e35f 100644 --- a/core/modules/locale/lib/Drupal/locale/StringDatabaseStorage.php +++ b/core/modules/locale/lib/Drupal/locale/StringDatabaseStorage.php @@ -287,40 +287,19 @@ protected function dbStringTable($string) { * * @param Drupal\locale\StringInterface $string * The string object. - * @param string $table - * (optional) The table name. * * @return array * Array with key fields if the string has all keys, or empty array if not. */ - protected function dbStringKeys($string, $table = NULL) { - $table = $table ? $table : $this->dbStringTable($string); - if ($table && $schema = drupal_get_schema($table)) { - $keys = $schema['primary key']; - $values = $string->getValues($keys); - if (count($values) == count($keys)) { - return $values; - } + protected function dbStringKeys($string) { + if ($string->isSource()) { + $keys = array('lid'); } - return NULL; - } - - /** - * Gets field values from a string object that are in the database table. - * - * @param Drupal\locale\StringInterface $string - * The string object. - * @param string $table - * (optional) The table name. - * - * @return array - * Array with field values indexed by field name. - */ - protected function dbStringValues($string, $table = NULL) { - $table = $table ? $table : $this->dbStringTable($string); - if ($table && $schema = drupal_get_schema($table)) { - $fields = array_keys($schema['fields']); - return $string->getValues($fields); + elseif ($string->isTranslation()) { + $keys = array('lid', 'language'); + } + if (!empty($keys) && ($values = $string->getValues($keys)) && count($keys) == count($values)) { + return $values; } else { return array(); @@ -328,27 +307,6 @@ protected function dbStringValues($string, $table = NULL) { } /** - * Sets default values from storage. - * - * @param Drupal\locale\StringInterface $string - * The string object. - * @param string $table - * (optional) The table name. - */ - protected function dbStringDefaults($string, $table = NULL) { - $table = $table ? $table : $this->dbStringTable($string); - if ($table && $schema = drupal_get_schema($table)) { - $values = array(); - foreach ($schema['fields'] as $name => $info) { - if (isset($info['default'])) { - $values[$name] = $info['default']; - } - } - $string->setValues($values, FALSE); - } - } - - /** * Loads multiple string objects. * * @param array $conditions @@ -504,9 +462,16 @@ protected function dbStringSelect(array $conditions, array $options = array()) { * If the string is not suitable for this storage, an exception ithrown. */ protected function dbStringInsert($string) { - if (($table = $this->dbStringTable($string)) && ($fields = $this->dbStringValues($string, $table))) { - $this->dbStringDefaults($string, $table); - return $this->connection->insert($table, $this->options) + if ($string->isSource()) { + $string->setValues(array('context' => '', 'version' => 'none'), FALSE); + $fields = $string->getValues(array('source', 'context', 'version')); + } + elseif ($string->isTranslation()) { + $string->setValues(array('customized' => 0), FALSE); + $fields = $string->getValues(array('lid', 'language', 'translation', 'customized')); + } + if (!empty($fields)) { + return $this->connection->insert($this->dbStringTable($string), $this->options) ->fields($fields) ->execute(); } @@ -531,13 +496,17 @@ protected function dbStringInsert($string) { * If the string is not suitable for this storage, an exception is thrown. */ protected function dbStringUpdate($string) { - if (($table = $this->dbStringTable($string)) && ($keys = $this->dbStringKeys($string, $table)) && - ($fields = $this->dbStringValues($string, $table)) && ($values = array_diff_key($fields, $keys))) - { - return $this->connection->merge($table, $this->options) - ->key($keys) - ->fields($values) - ->execute(); + if ($string->isSource()) { + $values = $string->getValues(array('source', 'context', 'version')); + } + elseif ($string->isTranslation()) { + $values = $string->getValues(array('translation', 'customized')); + } + if (!empty($values) && $keys = $this->dbStringKeys($string)) { + return $this->connection->merge($this->dbStringTable($string), $this->options) + ->key($keys) + ->fields($values) + ->execute(); } else { throw new StringStorageException(format_string('The string cannot be updated: @string', array( diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php index f17404a..4e178a2 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleConfigTranslationTest.php @@ -34,7 +34,7 @@ public static function getInfo() { public function setUp() { parent::setUp(); // Add a default locale storage for all these tests. - $this->storage = locale_storage(); + $this->storage = $this->container->get('locale.storage'); } /** diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleExportTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleExportTest.php index 7ae1bf7..954e74d 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleExportTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleExportTest.php @@ -79,9 +79,12 @@ function testExportTranslation() { ), 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'); + // Create string without translation in the locales_source table. + $this->container + ->get('locale.storage') + ->createString() + ->setString('February') + ->save(); // Export only customized French translations. $this->drupalPost('admin/config/regional/translate/export', array( diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleImportFunctionalTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleImportFunctionalTest.php index 0392c0f..15790a1 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleImportFunctionalTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleImportFunctionalTest.php @@ -269,7 +269,7 @@ function testConfigPoFile() { // Check for the source strings we are going to translate. Adding the // custom language should have made the process to export configuration // strings to interface translation executed. - $locale_storage = locale_storage(); + $locale_storage = $this->container->get('locale.storage'); foreach ($config_strings as $config_string) { $string = $locale_storage->findString(array('source' => $config_string[0], 'context' => '', 'type' => 'configuration')); $this->assertTrue($string, 'Configuration strings have been created upon installation.'); diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleJavascriptTranslation.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleJavascriptTranslation.php index d8e028f..de5dd08 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleJavascriptTranslation.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleJavascriptTranslation.php @@ -37,7 +37,13 @@ function testFileParsing() { _locale_parse_js_file($filename); // Get all of the source strings that were found. - foreach (locale_storage()->getStrings(array('type' => 'javascript', 'name' => $filename)) as $string) { + $strings = $this->container + ->get('locale.storage') + ->getStrings(array( + 'type' => 'javascript', + 'name' => $filename, + )); + foreach ($strings as $string) { $source_strings[$string->source] = $string->context; } // List of all strings that should be in the file. diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleStringTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleStringTest.php index 5dd4e23..37b796c 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleStringTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleStringTest.php @@ -45,7 +45,7 @@ public static function getInfo() { function setUp() { parent::setUp(); // Add a default locale storage for all these tests. - $this->storage = locale_storage(); + $this->storage = $this->container->get('locale.storage'); // Create two languages: Spanish and German. foreach (array('es', 'de') as $langcode) { $language = new Language(array('langcode' => $langcode)); @@ -134,11 +134,11 @@ function testStringSearchAPI() { $translate2 = $this->createAllTranslations($source2, array('customized' => LOCALE_CUSTOMIZED)); // Try quick search function with different field combinations. $langcode = 'es'; - $found = locale_storage()->findTranslation(array('language' => $langcode, 'source' => $source1->source, 'context' => $source1->context)); + $found = $this->storage->findTranslation(array('language' => $langcode, 'source' => $source1->source, 'context' => $source1->context)); $this->assertTrue($found && isset($found->language) && isset($found->translation) && !$found->isNew(), 'Translation found searching by source and context.'); $this->assertEqual($found->translation, $translate1[$langcode]->translation, 'Found the right translation.'); // Now try a translation not found. - $found = locale_storage()->findTranslation(array('language' => $langcode, 'source' => $source3->source, 'context' => $source3->context)); + $found = $this->storage->findTranslation(array('language' => $langcode, 'source' => $source3->source, 'context' => $source3->context)); $this->assertTrue($found && $found->lid == $source3->lid && !isset($found->translation) && $found->isNew(), 'Translation not found but source string found.'); // Load all translations. For next queries we'll be loading only translated strings. $only_translated = array('untranslated' => FALSE); diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php index f1c44dc..cb9cab2 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleTranslationTest.php @@ -74,7 +74,7 @@ function testStringTranslation() { // Add string. t($name, array(), array('langcode' => $langcode)); // Reset locale cache. - locale_reset(); + $this->container->get('string_translation')->reset(); $this->assertRaw('"edit-languages-' . $langcode .'-weight"', t('Language code found.')); $this->assertText(t($name), t('Test language added.')); $this->drupalLogout(); @@ -153,7 +153,7 @@ function testStringTranslation() { // 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(); + $this->container->get('string_translation')->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.')); @@ -369,7 +369,7 @@ function testStringSearch() { // Add string. t($name, array(), array('langcode' => $langcode)); // Reset locale cache. - locale_reset(); + $this->container->get('string_translation')->reset(); $this->drupalLogout(); // Search for the name. @@ -484,13 +484,13 @@ function testUICustomizedStrings(){ language_save($language); // Create test source string - $string = locale_storage()->createString(array( + $string = $this->container->get('locale.storage')->createString(array( 'source' => $this->randomName(100), 'context' => $this->randomName(20), ))->save(); // Create translation for new string and save it as non-customized. - $translation = locale_storage()->createTranslation(array( + $translation = $this->container->get('locale.storage')->createTranslation(array( 'lid' => $string->lid, 'language' => 'de', 'translation' => $this->randomName(100), @@ -498,7 +498,7 @@ function testUICustomizedStrings(){ ))->save(); // Reset locale cache. - locale_reset(); + $this->container->get('string_translation')->reset(); // Ensure non-customized translation string does appear if searching Non-customized translation. $search = array( diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php index ee2b0c3..adf8f32 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php @@ -73,7 +73,7 @@ function testUninstallProcess() { $this->drupalLogin($user); $this->drupalGet('admin/config/regional/translate/translate'); // Get any of the javascript strings to translate. - $js_strings = locale_storage()->getStrings(array('type' => 'javascript')); + $js_strings = $this->container->get('locale.storage')->getStrings(array('type' => 'javascript')); $string = reset($js_strings); $edit = array('string' => $string->source); $this->drupalPost('admin/config/regional/translate', $edit, t('Filter')); diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateTest.php index e5dccbd..feb11c8 100644 --- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateTest.php +++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUpdateTest.php @@ -226,9 +226,12 @@ private function setCurrentTranslations() { 'June' => 'Juni', ); foreach ($non_customized_translations as $source => $translation) { - $string = locale_storage()->createString(array('source' => $source, 'context' => $context)) + $string = $this->container->get('locale.storage')->createString(array( + 'source' => $source, + 'context' => $context, + )) ->save(); - $target = locale_storage()->createTranslation(array( + $target = $this->container->get('locale.storage')->createTranslation(array( 'lid' => $string->getId(), 'language' => $langcode, 'translation' => $translation, @@ -243,9 +246,12 @@ private function setCurrentTranslations() { 'May' => 'Mai_customized', ); foreach ($customized_translations as $source => $translation) { - $string = locale_storage()->createString(array('source' => $source, 'context' => $context)) - ->save(); - $target = locale_storage()->createTranslation(array( + $string = $this->container->get('locale.storage')->createString(array( + 'source' => $source, + 'context' => $context, + )) + ->save(); + $target = $this->container->get('locale.storage')->createTranslation(array( 'lid' => $string->getId(), 'language' => $langcode, 'translation' => $translation, diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module index 75e0a22..39ee236 100644 --- a/core/modules/locale/locale.module +++ b/core/modules/locale/locale.module @@ -314,7 +314,7 @@ function locale_language_update($language) { */ function locale_language_delete($language) { // Remove translations. - locale_storage()->deleteTranslations(array('language' => $language->langcode)); + Drupal::service('locale.storage')->deleteTranslations(array('language' => $language->langcode)); // Remove interface translation files. module_load_include('inc', 'locale', 'locale.bulk'); @@ -348,79 +348,6 @@ function locale_translatable_language_list() { } /** - * Provides interface translation services. - * - * This function is called from t() to translate a string if needed. - * - * @param $string - * A string to look up translation for. If omitted, all the - * cached strings will be returned in all languages already - * used on the page. - * @param $context - * The context of this string. - * @param $langcode - * Language code to use for the lookup. - */ -function locale($string = NULL, $context = NULL, $langcode = NULL) { - $language_interface = language(LANGUAGE_TYPE_INTERFACE); - - // Use the advanced drupal_static() pattern, since this is called very often. - static $drupal_static_fast; - if (!isset($drupal_static_fast)) { - $drupal_static_fast['locale'] = &drupal_static(__FUNCTION__, array('cache' => array(), 'exists' => NULL)); - } - $locale_t = &$drupal_static_fast['locale']['cache']; - $locale_exists = &$drupal_static_fast['locale']['exists']; - - // Check whether Locale module is actually installed and operational. - // The mere existence of locale() does not imply that Locale module is - // actually enabled and its database tables are installed. Since PHP code - // cannot be unloaded, this is typically the case in the environment that - // is executing a test. - if (!isset($locale_exists)) { - $locale_exists = function_exists('module_exists') && module_exists('locale'); - } - if (!$locale_exists) { - return $string; - } - - if (!isset($string)) { - // Return all cached strings if no string was specified - return $locale_t; - } - - $langcode = isset($langcode) ? $langcode : $language_interface->langcode; - - // Strings are cached by langcode, context and roles, using instances of the - // LocaleLookup class to handle string lookup and caching. - if (!isset($locale_t[$langcode][$context]) && isset($language_interface)) { - $locale_t[$langcode][$context] = new LocaleLookup($langcode, $context, locale_storage()); - } - return ($locale_t[$langcode][$context][$string] === TRUE ? $string : $locale_t[$langcode][$context][$string]); -} - -/** - * Reset static variables used by locale(). - */ -function locale_reset() { - drupal_static_reset('locale'); -} - -/** - * Gets the locale storage controller class . - * - * @return Drupal\locale\StringStorageInterface - */ -function locale_storage() { - $storage = &drupal_static(__FUNCTION__); - if (!isset($storage)) { - $options = array('target' => 'default'); - $storage = new StringDatabaseStorage(Database::getConnection($options['target']), $options); - } - return $storage; -} - -/** * Returns plural form index for a specific number. * * The index is computed from the formula of this language. @@ -719,12 +646,12 @@ function locale_library_info_alter(&$libraries, $module) { function locale_form_language_admin_overview_form_alter(&$form, &$form_state) { $languages = $form['languages']['#languages']; - $total_strings = locale_storage()->countStrings(); + $total_strings = Drupal::service('locale.storage')->countStrings(); $stats = array_fill_keys(array_keys($languages), array()); // If we have source strings, count translations and calculate progress. if (!empty($total_strings)) { - $translations = locale_storage()->countTranslations(); + $translations = Drupal::service('locale.storage')->countTranslations(); foreach ($translations as $langcode => $translated) { $stats[$langcode]['translated'] = $translated; if ($translated > 0) { @@ -1068,7 +995,7 @@ function _locale_refresh_translations($langcodes, $lids = array()) { if (!empty($langcodes)) { // Update javascript translations if any of the strings has a javascript // location, or if no string ids were provided, update all languages. - if (empty($lids) || ($strings = locale_storage()->getStrings(array('lid' => $lids, 'type' => 'javascript')))) { + if (empty($lids) || ($strings = Drupal::service('locale.storage')->getStrings(array('lid' => $lids, 'type' => 'javascript')))) { array_map('_locale_invalidate_js', $langcodes); } } @@ -1188,11 +1115,11 @@ function _locale_parse_js_file($filepath) { $string = implode('', preg_split('~(?findString(array('source' => $string, 'context' => $context)); + $source = Drupal::service('locale.storage')->findString(array('source' => $string, 'context' => $context)); if (!$source) { // We don't have the source string yet, thus we insert it into the database. - $source = locale_storage()->createString(array( + $source = Drupal::service('locale.storage')->createString(array( 'source' => $string, 'context' => $context, )); @@ -1261,7 +1188,7 @@ function _locale_rebuild_js($langcode = NULL) { 'translated' => TRUE, ); $translations = array(); - foreach (locale_storage()->getTranslations($conditions) as $data) { + foreach (Drupal::service('locale.storage')->getTranslations($conditions) as $data) { $translations[$data->context][$data->source] = $data->translation; } diff --git a/core/modules/locale/locale.pages.inc b/core/modules/locale/locale.pages.inc index a109f5f..2b221ef 100644 --- a/core/modules/locale/locale.pages.inc +++ b/core/modules/locale/locale.pages.inc @@ -57,7 +57,7 @@ function locale_translate_filter_load_strings() { } } - return locale_storage()->getTranslations($conditions, $options); + return Drupal::service('locale.storage')->getTranslations($conditions, $options); } /** @@ -402,7 +402,7 @@ function locale_translate_edit_form_submit($form, &$form_state) { // Preload all translations for strings in the form. $lids = array_keys($form_state['values']['strings']); $existing_translation_objects = array(); - foreach (locale_storage()->getTranslations(array('lid' => $lids, 'language' => $langcode, 'translated' => TRUE)) as $existing_translation_object) { + foreach (Drupal::service('locale.storage')->getTranslations(array('lid' => $lids, 'language' => $langcode, 'translated' => TRUE)) as $existing_translation_object) { $existing_translation_objects[$existing_translation_object->lid] = $existing_translation_object; } @@ -431,7 +431,7 @@ function locale_translate_edit_form_submit($form, &$form_state) { if ($is_changed) { // Only update or insert if we have a value to use. - $target = isset($existing_translation_objects[$lid]) ? $existing_translation_objects[$lid] : locale_storage()->createTranslation(array('lid' => $lid, 'language' => $langcode)); + $target = isset($existing_translation_objects[$lid]) ? $existing_translation_objects[$lid] : Drupal::service('locale.storage')->createTranslation(array('lid' => $lid, 'language' => $langcode)); $target->setPlurals($new_translation['translations']) ->setCustomized() ->save(); diff --git a/core/modules/locale/locale.services.yml b/core/modules/locale/locale.services.yml index 15763a4..cc39823 100644 --- a/core/modules/locale/locale.services.yml +++ b/core/modules/locale/locale.services.yml @@ -6,4 +6,12 @@ services: arguments: ['@language_manager', '@config.context'] locale.config.typed: class: Drupal\locale\LocaleConfigManager - arguments: ['@config.storage', '@config.storage.schema', '@config.storage.installer'] + arguments: ['@config.storage', '@config.storage.schema', '@config.storage.installer', '@locale.storage'] + locale.storage: + class: Drupal\locale\StringDatabaseStorage + arguments: ['@database'] + string_translator.locale.lookup: + class: Drupal\locale\LocaleTranslation + arguments: ['@locale.storage'] + tags: + - { name: string_translator } diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php index 6e791b3..4a9fac3 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php @@ -912,6 +912,9 @@ protected function prepareEnvironment() { // Reset and create a new service container. $this->container = new ContainerBuilder(); + // @todo Remove this once this class has no calls to t() and format_plural() + $this->container->register('string_translation', 'Drupal\Core\StringTranslation\TranslationManager'); + \Drupal::setContainer($this->container); // Unset globals. diff --git a/core/modules/system/lib/Drupal/system/Tests/Installer/InstallerLanguageTest.php b/core/modules/system/lib/Drupal/system/Tests/Installer/InstallerLanguageTest.php index 6e0d37b..c3308f7 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Installer/InstallerLanguageTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Installer/InstallerLanguageTest.php @@ -8,6 +8,7 @@ namespace Drupal\system\Tests\Installer; use Drupal\simpletest\WebTestBase; +use Drupal\Core\StringTranslation\Translator\FileTranslation; /** * Tests installer language detection. @@ -34,8 +35,6 @@ function setUp() { * Tests that the installer can find translation files. */ function testInstallerTranslationFiles() { - include_once DRUPAL_ROOT . '/core/includes/install.core.inc'; - // Different translation files would be found depending on which language // we are looking for. $expected_translation_files = array( @@ -45,8 +44,9 @@ function testInstallerTranslationFiles() { 'it' => array(), ); + $file_translation = new FileTranslation($GLOBALS['conf']['locale.settings']['translation.path']); foreach ($expected_translation_files as $langcode => $files_expected) { - $files_found = install_find_translation_files($langcode); + $files_found = $file_translation->findTranslationFiles($langcode); $this->assertTrue(count($files_found) == count($files_expected), format_string('@count installer languages found.', array('@count' => count($files_expected)))); foreach ($files_found as $file) { $this->assertTrue(in_array($file->filename, $files_expected), format_string('@file found.', array('@file' => $file->filename)));