View source
<?php
namespace Drupal\Tests\locale\Functional;
use Drupal\Core\Url;
use Drupal\Core\Database\Database;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Tests\BrowserTestBase;
use Drupal\Core\Language\LanguageInterface;
class LocaleImportFunctionalTest extends BrowserTestBase {
protected static $modules = [
'locale',
'dblog',
];
protected $defaultTheme = 'stark';
protected $adminUser;
protected $adminUserAccessSiteReports;
protected function setUp() : void {
parent::setUp();
$file_system = \Drupal::service('file_system');
$file_system
->copy(__DIR__ . '/../../../tests/test.de.po', 'translations://', FileSystemInterface::EXISTS_REPLACE);
$file_system
->copy(__DIR__ . '/../../../tests/test.xx.po', 'translations://', FileSystemInterface::EXISTS_REPLACE);
$this->adminUser = $this
->drupalCreateUser([
'administer languages',
'translate interface',
'access administration pages',
]);
$this->adminUserAccessSiteReports = $this
->drupalCreateUser([
'administer languages',
'translate interface',
'access administration pages',
'access site reports',
]);
$this
->drupalLogin($this->adminUser);
$this
->config('locale.settings')
->set('translation.import_enabled', TRUE)
->set('translation.use_source', LOCALE_TRANSLATION_USE_SOURCE_LOCAL)
->save();
}
public function testStandalonePoFile() {
$this
->importPoFile($this
->getPoFile(), [
'langcode' => 'fr',
]);
$this
->config('locale.settings');
$this
->assertSession()
->pageTextContains("The language French has been created.");
$this
->assertSession()
->pageTextContains("One translation file imported. 8 translations were added, 0 translations were updated and 0 translations were removed.");
$locale_plurals = \Drupal::service('locale.plural.formula')
->getNumberOfPlurals('fr');
$this
->assertEquals(2, $locale_plurals, 'Plural number initialized.');
$this
->assertSession()
->addressEquals(Url::fromRoute('locale.translate_page'));
$this
->importPoFile($this
->getBadPoFile(), [
'langcode' => 'fr',
]);
$this
->assertSession()
->pageTextContains("One translation file imported. 1 translations were added, 0 translations were updated and 0 translations were removed.");
$this
->assertSession()
->pageTextContains("2 translation strings were skipped because of disallowed or malformed HTML. See the log for details.");
$this
->drupalLogin($this->adminUserAccessSiteReports);
$this
->importPoFile($this
->getBadPoFile(), [
'langcode' => 'fr',
]);
$this
->assertSession()
->pageTextContains("2 translation strings were skipped because of disallowed or malformed HTML. See the log for details.");
$this
->drupalLogin($this->adminUser);
$this
->importPoFile($this
->getEmptyPoFile(), [
'langcode' => 'fr',
]);
$this
->assertSession()
->pageTextContains("One translation file could not be imported. See the log for details.");
$this
->drupalLogin($this->adminUserAccessSiteReports);
$this
->importPoFile($this
->getEmptyPoFile(), [
'langcode' => 'fr',
]);
$this
->assertSession()
->pageTextContains("One translation file could not be imported. See the log for details.");
$name = $this
->randomMachineName(16);
$this
->drupalGet('admin/config/regional/translate/import');
$this
->submitForm([
'langcode' => 'fr',
'files[file]' => $name,
], 'Import');
$this
->assertSession()
->addressEquals(Url::fromRoute('locale.translate_import'));
$this
->assertSession()
->pageTextContains('File to import not found.');
$this
->importPoFile($this
->getOverwritePoFile(), [
'langcode' => 'fr',
]);
$this
->assertSession()
->pageTextContains("One translation file imported. 1 translations were added, 0 translations were updated and 0 translations were removed.");
$search = [
'string' => 'Montag',
'langcode' => 'fr',
'translation' => 'translated',
];
$this
->drupalGet('admin/config/regional/translate');
$this
->submitForm($search, 'Filter');
$this
->assertSession()
->pageTextContains('No strings available.');
$locale_plurals = \Drupal::service('locale.plural.formula')
->getNumberOfPlurals('fr');
$this
->assertEquals(2, $locale_plurals, 'Plural numbers untouched.');
$this
->importPoFile($this
->getOverwritePoFile(), [
'langcode' => 'fr',
'overwrite_options[not_customized]' => TRUE,
]);
$this
->assertSession()
->pageTextContains("One translation file imported. 0 translations were added, 2 translations were updated and 0 translations were removed.");
$search = [
'string' => 'Montag',
'langcode' => 'fr',
'translation' => 'translated',
];
$this
->drupalGet('admin/config/regional/translate');
$this
->submitForm($search, 'Filter');
$this
->assertSession()
->pageTextNotContains('No strings available.');
$locale_plurals = \Drupal::service('locale.plural.formula')
->reset()
->getNumberOfPlurals('fr');
$this
->assertEquals(3, $locale_plurals, 'Plural numbers changed.');
$this
->importPoFile($this
->getCustomPoFile(), [
'langcode' => 'fr',
'customized' => TRUE,
]);
$this
->assertSession()
->pageTextContains("One translation file imported. 6 translations were added, 0 translations were updated and 0 translations were removed.");
$count = Database::getConnection()
->select('locales_target')
->condition('customized', 1)
->countQuery()
->execute()
->fetchField();
$this
->assertEquals(6, $count, 'Customized translations successfully imported.');
$this
->importPoFile($this
->getCustomOverwritePoFile(), [
'langcode' => 'fr',
'overwrite_options[not_customized]' => TRUE,
'overwrite_options[customized]' => FALSE,
]);
$this
->assertSession()
->pageTextContains("One translation file imported. 1 translations were added, 0 translations were updated and 0 translations were removed.");
$search = [
'string' => 'januari',
'langcode' => 'fr',
'translation' => 'translated',
];
$this
->drupalGet('admin/config/regional/translate');
$this
->submitForm($search, 'Filter');
$this
->assertSession()
->pageTextContains('No strings available.');
$this
->importPoFile($this
->getCustomOverwritePoFile(), [
'langcode' => 'fr',
'overwrite_options[not_customized]' => FALSE,
'overwrite_options[customized]' => TRUE,
]);
$this
->assertSession()
->pageTextContains("One translation file imported. 0 translations were added, 2 translations were updated and 0 translations were removed.");
$search = [
'string' => 'januari',
'langcode' => 'fr',
'translation' => 'translated',
];
$this
->drupalGet('admin/config/regional/translate');
$this
->submitForm($search, 'Filter');
$this
->assertSession()
->pageTextNotContains('No strings available.');
}
public function testLanguageContext() {
$this
->importPoFile($this
->getPoFileWithContext(), [
'langcode' => 'hr',
]);
$this
->assertSame('Svibanj', (string) t('May', [], [
'langcode' => 'hr',
'context' => 'Long month name',
]), 'Long month name context is working.');
$this
->assertSame('Svi.', (string) t('May', [], [
'langcode' => 'hr',
]), 'Default context is working.');
}
public function testEmptyMsgstr() {
$langcode = 'hu';
$this
->importPoFile($this
->getPoFileWithMsgstr(), [
'langcode' => $langcode,
]);
$this
->assertSession()
->pageTextContains("One translation file imported. 1 translations were added, 0 translations were updated and 0 translations were removed.");
$this
->assertSame('Műveletek', (string) t('Operations', [], [
'langcode' => $langcode,
]), 'String imported and translated.');
$this
->importPoFile($this
->getPoFileWithEmptyMsgstr(), [
'langcode' => $langcode,
'overwrite_options[not_customized]' => TRUE,
]);
$this
->assertSession()
->pageTextContains("One translation file imported. 0 translations were added, 0 translations were updated and 1 translations were removed.");
$str = "Operations";
$search = [
'string' => $str,
'langcode' => $langcode,
'translation' => 'untranslated',
];
$this
->drupalGet('admin/config/regional/translate');
$this
->submitForm($search, 'Filter');
$this
->assertSession()
->pageTextContains($str);
}
public function testConfigPoFile() {
$config_strings = [
'system.maintenance' => [
'@site is currently under maintenance. We should be back shortly. Thank you for your patience.',
'@site karbantartás alatt áll. Rövidesen visszatérünk. Köszönjük a türelmet.',
'message',
],
'user.role.anonymous' => [
'Anonymous user',
'Névtelen felhasználó',
'label',
],
];
$langcode = 'xx';
$edit = [
'predefined_langcode' => 'custom',
'langcode' => $langcode,
'label' => $this
->randomMachineName(16),
'direction' => LanguageInterface::DIRECTION_LTR,
];
$this
->drupalGet('admin/config/regional/language/add');
$this
->submitForm($edit, 'Add custom language');
$locale_storage = $this->container
->get('locale.storage');
foreach ($config_strings as $config_string) {
$string = $locale_storage
->findString([
'source' => $config_string[0],
'context' => '',
'type' => 'configuration',
]);
$this
->assertNotEmpty($string, 'Configuration strings have been created upon installation.');
}
$this
->importPoFile($this
->getPoFileWithConfig(), [
'langcode' => $langcode,
]);
foreach ($config_strings as $config_string) {
$search = [
'string' => $config_string[0],
'langcode' => $langcode,
'translation' => 'all',
];
$this
->drupalGet('admin/config/regional/translate');
$this
->submitForm($search, 'Filter');
$this
->assertSession()
->pageTextContains($config_string[1]);
}
$overrides = \Drupal::service('language.config_factory_override');
foreach ($config_strings as $config_key => $config_string) {
$override = $overrides
->getOverride($langcode, $config_key);
$this
->assertEquals($override
->get($config_string[2]), $config_string[1]);
}
}
public function testConfigTranslationImportingPoFile() {
$langcode = 'de';
$this
->importPoFile($this
->getPoFileWithConfigDe(), [
'langcode' => $langcode,
]);
$config = \Drupal::languageManager()
->getLanguageConfigOverride($langcode, 'user.settings');
$this
->assertEquals('Anonymous German', $config
->get('anonymous'));
}
public function testCreatedLanguageTranslation() {
$this
->importPoFile($this
->getPoFileWithConfigDe(), [
'langcode' => 'de',
]);
$override = \Drupal::languageManager()
->getLanguageConfigOverride('de', 'language.entity.de');
$this
->assertEquals('Deutsch', $override
->get('label'));
}
public function importPoFile($contents, array $options = []) {
$file_system = \Drupal::service('file_system');
$name = $file_system
->tempnam('temporary://', "po_") . '.po';
file_put_contents($name, $contents);
$options['files[file]'] = $name;
$this
->drupalGet('admin/config/regional/translate/import');
$this
->submitForm($options, 'Import');
$file_system
->unlink($name);
}
public function getPoFile() {
return <<<EOF
msgid ""
msgstr ""
"Project-Id-Version: Drupal 8\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
msgid "One sheep"
msgid_plural "@count sheep"
msgstr[0] "un mouton"
msgstr[1] "@count moutons"
msgid "Monday"
msgstr "lundi"
msgid "Tuesday"
msgstr "mardi"
msgid "Wednesday"
msgstr "mercredi"
msgid "Thursday"
msgstr "jeudi"
msgid "Friday"
msgstr "vendredi"
msgid "Saturday"
msgstr "samedi"
msgid "Sunday"
msgstr "dimanche"
EOF;
}
public function getEmptyPoFile() {
return '';
}
public function getBadPoFile() {
return <<<EOF
msgid ""
msgstr ""
"Project-Id-Version: Drupal 8\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
msgid "Save configuration"
msgstr "Enregistrer la configuration"
msgid "edit"
msgstr "modifier<img SRC="javascript:alert(\\'xss\\');">"
msgid "delete"
msgstr "supprimer<script>alert('xss');</script>"
EOF;
}
public function getOverwritePoFile() {
return <<<EOF
msgid ""
msgstr ""
"Project-Id-Version: Drupal 8\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\\n"
msgid "Monday"
msgstr "Montag"
msgid "Day"
msgstr "Jour"
EOF;
}
public function getCustomPoFile() {
return <<<EOF
msgid ""
msgstr ""
"Project-Id-Version: Drupal 8\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
msgid "One dog"
msgid_plural "@count dogs"
msgstr[0] "un chien"
msgstr[1] "@count chiens"
msgid "January"
msgstr "janvier"
msgid "February"
msgstr "février"
msgid "March"
msgstr "mars"
msgid "April"
msgstr "avril"
msgid "June"
msgstr "juin"
EOF;
}
public function getCustomOverwritePoFile() {
return <<<EOF
msgid ""
msgstr ""
"Project-Id-Version: Drupal 8\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
msgid "January"
msgstr "januari"
msgid "February"
msgstr "februari"
msgid "July"
msgstr "juillet"
EOF;
}
public function getPoFileWithContext() {
return <<<EOF
msgid ""
msgstr ""
"Project-Id-Version: Drupal 8\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\\n"
msgctxt "Long month name"
msgid "May"
msgstr "Svibanj"
msgid "May"
msgstr "Svi."
EOF;
}
public function getPoFileWithEmptyMsgstr() {
return <<<EOF
msgid ""
msgstr ""
"Project-Id-Version: Drupal 8\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
msgid "Operations"
msgstr ""
EOF;
}
public function getPoFileWithMsgstr() {
return <<<EOF
msgid ""
msgstr ""
"Project-Id-Version: Drupal 8\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
msgid "Operations"
msgstr "Műveletek"
msgid "Will not appear in Drupal core, so we can ensure the test passes"
msgstr ""
EOF;
}
public function getPoFileWithConfig() {
return <<<EOF
msgid ""
msgstr ""
"Project-Id-Version: Drupal 8\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
msgid "@site is currently under maintenance. We should be back shortly. Thank you for your patience."
msgstr "@site karbantartás alatt áll. Rövidesen visszatérünk. Köszönjük a türelmet."
msgid "Anonymous user"
msgstr "Névtelen felhasználó"
EOF;
}
public function getPoFileWithConfigDe() {
return <<<EOF
msgid ""
msgstr ""
"Project-Id-Version: Drupal 8\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\\n"
msgid "Anonymous"
msgstr "Anonymous German"
msgid "German"
msgstr "Deutsch"
EOF;
}
}