Issue #2575945 by Sutharsan, mstrelan, tobiasb, ranjith_kumar_k_u, andypost, ericdsd, smustgrave, Ammaletu: A new module version is not recognized by interface translation update

merge-requests/5828/head
Lee Rowlands 2023-12-22 15:04:56 +10:00
parent 3e49eeb716
commit 9e290d8cc7
No known key found for this signature in database
GPG Key ID: 2B829A3DF9204DC4
5 changed files with 136 additions and 4 deletions

View File

@ -23,6 +23,43 @@ use Psr\Http\Message\UriInterface;
// Follow-up issue: https://www.drupal.org/node/1834298.
require_once __DIR__ . '/locale.translation.inc';
/**
* Implements callback_batch_operation().
*
* Checks for changed project versions, and cleans-up data from the old version.
* For example when a module is updated. This will make the translation import
* system use translations that match the current version.
*
* @param string $project
* Machine name of the project for which to check the translation status.
* @param string $langcode
* Language code of the language for which to check the translation.
* @param array|\ArrayAccess $context
* The batch context.
*/
function locale_translation_batch_version_check(string $project, string $langcode, array|\ArrayAccess &$context) {
$locale_project = \Drupal::service('locale.project')->get($project);
if (empty($locale_project)) {
return;
}
$status = \Drupal::keyValue('locale.translation_status')->get($project);
if (!isset($status[$langcode])) {
return;
}
if ($locale_project['version'] == $status[$langcode]->version) {
return;
}
\Drupal::moduleHandler()->loadInclude('locale', 'bulk.inc');
locale_translation_status_delete_projects([$project]);
locale_translate_delete_translation_files([$project]);
$context['message'] = t('Checked version of %project.', ['%project' => $project]);
}
/**
* Implements callback_batch_operation().
*

View File

@ -267,7 +267,8 @@ function _locale_translation_batch_status_operations($projects, $langcodes, $opt
foreach ($projects as $project) {
foreach ($langcodes as $langcode) {
// Check status of local and remote translation sources.
// Check version and status translation sources.
$operations[] = ['locale_translation_batch_version_check', [$project, $langcode]];
$operations[] = ['locale_translation_batch_status_check', [$project, $langcode, $options]];
}
}

View File

@ -0,0 +1,86 @@
<?php
namespace Drupal\Tests\locale\Functional;
use Drupal\Core\StreamWrapper\PublicStream;
use Drupal\language\Entity\ConfigurableLanguage;
/**
* Tests how translations are handled when a project gets updated.
*
* @group locale
*/
class LocaleTranslationChangeProjectVersionTest extends LocaleUpdateBase {
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
\Drupal::moduleHandler()->loadInclude('locale', 'inc', 'locale.batch');
ConfigurableLanguage::createFromLangcode('de')->save();
\Drupal::state()->set('locale.test_projects_alter', TRUE);
\Drupal::state()->set('locale.remove_core_project', TRUE);
// Setup the environment.
$config = $this->config('locale.settings');
$public_path = PublicStream::basePath();
$this->setTranslationsDirectory($public_path . '/local');
$config
->set('translation.default_filename', '%project-%version.%language._po')
->set('translation.use_source', LOCALE_TRANSLATION_USE_SOURCE_LOCAL)
->save();
// This test uses .po files for the old translation file instead of the ._po
// files because locale_translate_get_interface_translation_files() (used to
// delete old translation files) only works with .po files.
// The new translation file uses _po.
// Old version: 8.x-1.0; New version: 8.x-1.1.
$this->makePoFile('remote/all/contrib_module_one', 'contrib_module_one-8.x-1.0.de.po', $this->timestampOld, []);
$this->makePoFile('remote/all/contrib_module_one', 'contrib_module_one-8.x-1.1.de._po', $this->timestampNew, []);
$this->makePoFile('local', 'contrib_module_one-8.x-1.0.de.po', $this->timestampOld, []);
// Initialize the projects status and change the project version to the old
// version. This makes the code update the module translation to the new
// version when the (batch) update script is triggered.
$status = locale_translation_get_status();
$status['contrib_module_one']['de']->version = '8.x-1.0';
\Drupal::keyValue('locale.translation_status')->setMultiple($status);
}
/**
* Tests update translations when project version changes.
*/
public function testUpdateImportSourceRemote() {
// Verify that the project status has the old version.
$status = locale_translation_get_status(['contrib_module_one']);
$this->assertEquals('8.x-1.0', $status['contrib_module_one']['de']->version);
// Verify that the old translation file exists and the new does not exist.
$this->assertFileExists('translations://contrib_module_one-8.x-1.0.de.po');
$this->assertFileDoesNotExist('translations://contrib_module_one-8.x-1.1.de._po');
// Run batch tasks.
$context = [];
locale_translation_batch_version_check('contrib_module_one', 'de', $context);
locale_translation_batch_status_check('contrib_module_one', 'de', [], $context);
locale_translation_batch_fetch_download('contrib_module_one', 'de', $context);
// Verify that the project status has the new version.
$status = locale_translation_get_status(['contrib_module_one']);
$this->assertEquals('8.x-1.1', $status['contrib_module_one']['de']->version);
// Verify that the old translation file was removed and the new was
// downloaded.
$this->assertFileDoesNotExist('translations://contrib_module_one-8.x-1.0.de.po');
$this->assertFileExists('translations://contrib_module_one-8.x-1.1.de._po');
}
}

View File

@ -135,10 +135,11 @@ EOF;
}
\Drupal::service('file_system')->prepareDirectory($path, FileSystemInterface::CREATE_DIRECTORY);
$fileUri = $path . '/' . $filename;
$file = File::create([
'uid' => 1,
'filename' => $filename,
'uri' => $path . '/' . $filename,
'uri' => $fileUri,
'filemime' => 'text/x-gettext-translation',
'timestamp' => $timestamp,
]);
@ -146,6 +147,9 @@ EOF;
file_put_contents($file->getFileUri(), $po_header . $text);
touch(\Drupal::service('file_system')->realpath($file->getFileUri()), $timestamp);
$file->save();
$this->assertTrue(file_exists($fileUri));
$this->assertEquals($timestamp, filemtime($fileUri));
}
/**

View File

@ -98,8 +98,12 @@ class LocaleUpdateCronTest extends LocaleUpdateBase {
locale_cron();
// Check whether tasks are added to the queue.
// Expected tasks:
// - locale_translation_batch_version_check
// - locale_translation_batch_status_check
// - locale_translation_batch_status_finished.
$queue = \Drupal::queue('locale_translation', TRUE);
$this->assertEquals(2, $queue->numberOfItems(), 'Queue holds tasks for one project.');
$this->assertEquals(3, $queue->numberOfItems(), 'Queue holds tasks for one project.');
$item = $queue->claimItem();
$queue->releaseItem($item);
$this->assertEquals('contrib_module_two', $item->data[1][0], 'Queue holds tasks for contrib module one.');
@ -110,7 +114,7 @@ class LocaleUpdateCronTest extends LocaleUpdateBase {
// Check whether no more tasks are added to the queue.
$queue = \Drupal::queue('locale_translation', TRUE);
$this->assertEquals(2, $queue->numberOfItems(), 'Queue holds tasks for one project.');
$this->assertEquals(3, $queue->numberOfItems(), 'Queue holds tasks for one project.');
// Ensure last checked is updated to a greater time than the initial value.
sleep(1);