Issue #2139467 by vaplas, Gábor Hojtsy, andypost, Sutharsan, alexpott, dillix: format_plural() does not handle D7 translations with a plural form after @count
parent
9b874acf9f
commit
3f49bda7e7
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Post-update functions for Locale module.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear cache to ensure plural translations are removed from it.
|
||||||
|
*/
|
||||||
|
function locale_post_update_clear_cache_for_old_translations() {
|
||||||
|
// Remove cache of translations, like '@count[2] words'.
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ use Drupal\Core\Cache\CacheCollector;
|
||||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||||
use Drupal\Core\Language\LanguageManagerInterface;
|
use Drupal\Core\Language\LanguageManagerInterface;
|
||||||
use Drupal\Core\Lock\LockBackendInterface;
|
use Drupal\Core\Lock\LockBackendInterface;
|
||||||
|
use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
|
||||||
use Symfony\Component\HttpFoundation\RequestStack;
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -172,6 +173,12 @@ class LocaleLookup extends CacheCollector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_string($value) && strpos($value, PluralTranslatableMarkup::DELIMITER) !== FALSE) {
|
||||||
|
// Community translations imported from localize.drupal.org as well as
|
||||||
|
// migrated translations may contain @count[number].
|
||||||
|
$value = preg_replace('!@count\[\d+\]!', '@count', $value);
|
||||||
|
}
|
||||||
|
|
||||||
$this->storage[$offset] = $value;
|
$this->storage[$offset] = $value;
|
||||||
// Disabling the usage of string caching allows a module to watch for
|
// Disabling the usage of string caching allows a module to watch for
|
||||||
// the exact list of strings used on a page. From a performance
|
// the exact list of strings used on a page. From a performance
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace Drupal\Tests\locale\Functional;
|
namespace Drupal\Tests\locale\Functional;
|
||||||
|
|
||||||
|
use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
|
||||||
use Drupal\language\Entity\ConfigurableLanguage;
|
use Drupal\language\Entity\ConfigurableLanguage;
|
||||||
use Drupal\Tests\BrowserTestBase;
|
use Drupal\Tests\BrowserTestBase;
|
||||||
|
|
||||||
|
@ -55,4 +56,45 @@ class LocaleLocaleLookupTest extends BrowserTestBase {
|
||||||
$this->assertEqual($context['operation'], 'locale_lookup');
|
$this->assertEqual($context['operation'], 'locale_lookup');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test old plural style @count[number] fix.
|
||||||
|
*
|
||||||
|
* @dataProvider providerTestFixOldPluralStyle
|
||||||
|
*/
|
||||||
|
public function testFixOldPluralStyle($translation_value, $expected) {
|
||||||
|
$string_storage = \Drupal::service('locale.storage');
|
||||||
|
$string = $string_storage->findString(['source' => 'Member for', 'context' => '']);
|
||||||
|
$lid = $string->getId();
|
||||||
|
$string_storage->createTranslation([
|
||||||
|
'lid' => $lid,
|
||||||
|
'language' => 'fr',
|
||||||
|
'translation' => $translation_value,
|
||||||
|
])->save();
|
||||||
|
_locale_refresh_translations(['fr'], [$lid]);
|
||||||
|
|
||||||
|
// Check that 'count[2]' was fixed for render value.
|
||||||
|
$this->drupalGet('');
|
||||||
|
$this->assertSession()->pageTextContains($expected);
|
||||||
|
|
||||||
|
// Check that 'count[2]' was saved for source value.
|
||||||
|
$translation = $string_storage->findTranslation(['language' => 'fr', 'lid' => $lid])->translation;
|
||||||
|
$this->assertSame($translation_value, $translation, 'Source value not changed');
|
||||||
|
$this->assertNotFalse(strpos($translation, '@count[2]'), 'Source value contains @count[2]');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides data for testFixOldPluralStyle().
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* An array of test data:
|
||||||
|
* - translation value
|
||||||
|
* - expected result
|
||||||
|
*/
|
||||||
|
public function providerTestFixOldPluralStyle() {
|
||||||
|
return [
|
||||||
|
'non-plural translation' => ['@count[2] non-plural test', '@count[2] non-plural test'],
|
||||||
|
'plural translation' => ['@count[2] plural test' . PluralTranslatableMarkup::DELIMITER, '@count plural test'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace Drupal\Tests\locale\Unit;
|
namespace Drupal\Tests\locale\Unit;
|
||||||
|
|
||||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||||
|
use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
|
||||||
use Drupal\locale\LocaleLookup;
|
use Drupal\locale\LocaleLookup;
|
||||||
use Drupal\Tests\UnitTestCase;
|
use Drupal\Tests\UnitTestCase;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
@ -266,4 +267,66 @@ class LocaleLookupTest extends UnitTestCase {
|
||||||
$this->assertTrue($locale_lookup->get('test'));
|
$this->assertTrue($locale_lookup->get('test'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests locale lookups with old plural style of translations.
|
||||||
|
*
|
||||||
|
* @param array $translations
|
||||||
|
* The source with translations.
|
||||||
|
* @param string $langcode
|
||||||
|
* The language code of translation string.
|
||||||
|
* @param string $string
|
||||||
|
* The string for translation.
|
||||||
|
* @param bool $is_fix
|
||||||
|
* The flag about expected fix translation.
|
||||||
|
*
|
||||||
|
* @covers ::resolveCacheMiss
|
||||||
|
* @dataProvider providerFixOldPluralTranslationProvider
|
||||||
|
*/
|
||||||
|
public function testFixOldPluralStyleTranslations($translations, $langcode, $string, $is_fix) {
|
||||||
|
$this->storage->expects($this->any())
|
||||||
|
->method('findTranslation')
|
||||||
|
->will($this->returnCallback(function ($argument) use ($translations) {
|
||||||
|
if (isset($translations[$argument['language']][$argument['source']])) {
|
||||||
|
return (object) ['translation' => $translations[$argument['language']][$argument['source']]];
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}));
|
||||||
|
$this->languageManager->expects($this->any())
|
||||||
|
->method('getFallbackCandidates')
|
||||||
|
->will($this->returnCallback(function (array $context = []) {
|
||||||
|
switch ($context['langcode']) {
|
||||||
|
case 'by':
|
||||||
|
return ['ru'];
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
$this->cache->expects($this->once())
|
||||||
|
->method('get')
|
||||||
|
->with('locale:' . $langcode . '::anonymous', FALSE);
|
||||||
|
|
||||||
|
$locale_lookup = new LocaleLookup($langcode, '', $this->storage, $this->cache, $this->lock, $this->configFactory, $this->languageManager, $this->requestStack);
|
||||||
|
$this->assertSame($is_fix, strpos($locale_lookup->get($string), '@count[2]') === FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides test data for testResolveCacheMissWithFallback().
|
||||||
|
*/
|
||||||
|
public function providerFixOldPluralTranslationProvider() {
|
||||||
|
$translations = [
|
||||||
|
'by' => [
|
||||||
|
'word1' => '@count[2] word-by',
|
||||||
|
'word2' => implode(PluralTranslatableMarkup::DELIMITER, ['word-by', '@count[2] word-by']),
|
||||||
|
],
|
||||||
|
'ru' => [
|
||||||
|
'word3' => '@count[2] word-ru',
|
||||||
|
'word4' => implode(PluralTranslatableMarkup::DELIMITER, ['word-ru', '@count[2] word-ru']),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
return [
|
||||||
|
'no-plural' => [$translations, 'by', 'word1', FALSE],
|
||||||
|
'no-plural from other language' => [$translations, 'by', 'word3', FALSE],
|
||||||
|
'plural' => [$translations, 'by', 'word2', TRUE],
|
||||||
|
'plural from other language' => [$translations, 'by', 'word4', TRUE],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue