Commit bda20663 authored by alexpott's avatar alexpott

Issue #2419897 by penyaskito, Wim Leers, webflo: Javascript translations are...

Issue #2419897 by penyaskito, Wim Leers, webflo: Javascript translations are loaded in the wrong order due to missing dependencies
parent d8aa1a87
......@@ -5,6 +5,7 @@
"globals": {
"Drupal": true,
"drupalSettings": true,
"drupalTranslations": true,
"domready": true,
"jQuery": true,
"_": true,
......
......@@ -62,8 +62,7 @@ drupalSettings:
currentPathIsAdmin: null
isFront: null
currentLanguage: null
locale:
pluralDelimiter: null
pluralDelimiter: null
drupal.active-link:
version: VERSION
......
/**
* Base framework for Drupal-specific JavaScript, behaviors, and settings.
*/
window.Drupal = {behaviors: {}, locale: {}};
window.Drupal = {behaviors: {}};
// Class indicating that JS is enabled; used for styling purpose.
document.documentElement.className += ' js';
......@@ -13,7 +13,7 @@ if (window.jQuery) {
// JavaScript should be made compatible with libraries other than jQuery by
// wrapping it in an anonymous closure.
(function (domready, Drupal, drupalSettings) {
(function (domready, Drupal, drupalSettings, drupalTranslations) {
"use strict";
......@@ -312,8 +312,8 @@ if (window.jQuery) {
options.context = options.context || '';
// Fetch the localized version of the string.
if (Drupal.locale.strings && Drupal.locale.strings[options.context] && Drupal.locale.strings[options.context][str]) {
str = Drupal.locale.strings[options.context][str];
if (typeof drupalTranslations !== 'undefined' && drupalTranslations.strings && drupalTranslations.strings[options.context] && drupalTranslations.strings[options.context][str]) {
str = drupalTranslations.strings[options.context][str];
}
if (args) {
......@@ -366,13 +366,13 @@ if (window.jQuery) {
args = args || {};
args['@count'] = count;
var pluralDelimiter = drupalSettings.locale.pluralDelimiter,
var pluralDelimiter = drupalSettings.pluralDelimiter,
translations = Drupal.t(singular + pluralDelimiter + plural, args, options).split(pluralDelimiter),
index = 0;
// Determine the index of the plural form.
if (Drupal.locale.pluralFormula) {
index = count in Drupal.locale.pluralFormula ? Drupal.locale.pluralFormula[count] : Drupal.locale.pluralFormula['default'];
if (typeof drupalTranslations !== 'undefined' && drupalTranslations.pluralFormula) {
index = count in drupalTranslations.pluralFormula ? drupalTranslations.pluralFormula[count] : drupalTranslations.pluralFormula['default'];
}
else if (args['@count'] !== 1) {
index = 1;
......@@ -429,4 +429,4 @@ if (window.jQuery) {
return '<em class="placeholder">' + Drupal.checkPlain(str) + '</em>';
};
})(domready, Drupal, window.drupalSettings);
})(domready, Drupal, window.drupalSettings, window.drupalTranslations);
......@@ -18,3 +18,12 @@ drupal.locale.datepicker:
- core/jquery
- core/drupal
- core/drupalSettings
translations:
# No sensible version can be specified, since the translations may change at
# any time.
js:
# This file does not actually exist; it's a placeholder file that will be
# overriden by locale_js_alter(), to use the file that contains the actual
# translations, for the language used in the current request.
locale.translation.js: {}
......@@ -447,14 +447,32 @@ function locale_cache_flush() {
* Implements hook_js_alter().
*/
function locale_js_alter(&$javascript, AttachedAssetsInterface $assets) {
// @todo remove this in https://www.drupal.org/node/2421323
$files = array();
foreach ($javascript as $item) {
if (isset($item['type']) && $item['type'] == 'file') {
// Ignore the JS translation placeholder file.
if ($item['data'] === 'core/modules/locale/locale.translation.js') {
continue;
}
$files[] = $item['data'];
}
}
if ($translation_file = locale_js_translate($files)) {
$javascript[$translation_file] = drupal_js_defaults($translation_file);
// Replace the placeholder file with the actual JS translation file.
$placeholder_file = 'core/modules/locale/locale.translation.js';
if (isset($javascript[$placeholder_file])) {
if ($translation_file = locale_js_translate($files)) {
$js_translation_asset = &$javascript[$placeholder_file];
$js_translation_asset['data'] = $translation_file;
// @todo Remove this when https://www.drupal.org/node/1945262 lands.
// Decrease the weight so that the translation file is loaded first.
$js_translation_asset['weight'] = $javascript['core/misc/drupal.js']['weight'] - 0.001;
}
else {
// If no translation file exists, then remove the placeholder JS asset.
unset($javascript[$placeholder_file]);
}
}
}
......@@ -537,6 +555,15 @@ function locale_library_info_alter(array &$libraries, $module) {
'firstDay' => NULL,
];
}
// When the locale module is enabled, we update the core/drupal library to
// have a dependency on the locale/translations library, which provides
// window.drupalTranslations, containing the translations for all strings in
// JavaScript assets in the current language.
// @see locale_js_alter()
if ($module === 'core' && isset($libraries['drupal'])) {
$libraries['drupal']['dependencies'][] = 'locale/translations';
}
}
/**
......@@ -1203,7 +1230,7 @@ function _locale_rebuild_js($langcode = NULL) {
$data['pluralFormula'] = $locale_plurals[$language->getId()]['formula'];
}
$data = 'Drupal.locale = ' . Json::encode($data) . ';';
$data = 'window.drupalTranslations = ' . Json::encode($data) . ';';
$data_hash = Crypt::hashBase64($data);
}
......
......@@ -7,6 +7,7 @@
namespace Drupal\locale\Tests;
use Drupal\Core\Language\LanguageInterface;
use Drupal\simpletest\WebTestBase;
use Drupal\Component\Utility\String;
......@@ -93,4 +94,57 @@ public function testFileParsing() {
$this->assertEqual(count($source_strings), count($test_strings), 'Found correct number of source strings.');
}
/**
* Assert translations JS is added before drupal.js, because it depends on it.
*/
public function testLocaleTranslationJsDependencies() {
// User to add and remove language.
$admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages', 'translate interface'));
// Add custom language.
$this->drupalLogin($admin_user);
// Code for the language.
$langcode = 'es';
// The English name for the language.
$name = $this->randomMachineName(16);
// The domain prefix.
$prefix = $langcode;
$edit = array(
'predefined_langcode' => 'custom',
'langcode' => $langcode,
'label' => $name,
'direction' => LanguageInterface::DIRECTION_LTR,
);
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add custom language'));
// Set path prefix.
$edit = array("prefix[$langcode]" => $prefix);
$this->drupalPostForm('admin/config/regional/language/detection/url', $edit, t('Save configuration'));
// This forces locale.admin.js string sources to be imported, which contains
// the next translation.
$this->drupalGet($prefix . '/admin/config/regional/translate');
// Translate a string in locale.admin.js to our new language.
$strings = \Drupal::service('locale.storage')
->getStrings(array(
'source' => 'Show description',
'type' => 'javascript',
'name' => 'core/modules/locale/locale.admin.js',
));
$string = $strings[0];
$this->drupalPostForm(NULL, ['string' => 'Show description'], t('Filter'));
$edit = ['strings[' . $string->lid . '][translations][0]' => $this->randomString(16)];
$this->drupalPostForm(NULL, $edit, t('Save translations'));
// Calculate the filename of the JS including the translations.
$js_translation_files = \Drupal::state()->get('locale.translation.javascript');
$js_filename = $prefix . '_' . $js_translation_files[$prefix] . '.js';
// Assert translations JS is included before drupal.js.
$this->assertTrue(strpos($this->content, $js_filename) < strpos($this->content, 'core/misc/drupal.js'), 'Translations are included before Drupal.t.');
}
}
......@@ -225,7 +225,7 @@ function testSettings() {
// Tests whether altering JavaScript settings via hook_js_settings_alter()
// is working as expected.
// @see common_test_js_settings_alter()
$this->assertIdentical($parsed_settings['locale']['pluralDelimiter'], '☃');
$this->assertIdentical($parsed_settings['pluralDelimiter'], '☃');
$this->assertIdentical($parsed_settings['foo'], 'bar');
}
......
......@@ -661,8 +661,8 @@ function system_js_settings_alter(&$settings, AttachedAssetsInterface $assets) {
$settings['path'][$key] = $value;
}
}
if (!isset($settings['locale']['pluralDelimiter'])) {
$settings['locale']['pluralDelimiter'] = LOCALE_PLURAL_DELIMITER;
if (!isset($settings['pluralDelimiter'])) {
$settings['pluralDelimiter'] = LOCALE_PLURAL_DELIMITER;
}
// Now generate the values for the core/drupal.ajax library.
......
......@@ -353,8 +353,8 @@ function common_test_page_attachments_alter(array &$page) {
*/
function common_test_js_settings_alter(&$settings, AttachedAssetsInterface $assets) {
// Modify an existing setting.
if (array_key_exists('pluralDelimiter', $settings['locale'])) {
$settings['locale']['pluralDelimiter'] = '☃';
if (array_key_exists('pluralDelimiter', $settings)) {
$settings['pluralDelimiter'] = '☃';
}
// Add a setting.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment