Skip to content
Snippets Groups Projects
Verified Commit e7e4e0e7 authored by Dave Long's avatar Dave Long
Browse files

Issue #3403337 by alexpott, quietone, Akhil Babu, vakulrai, smustgrave, Gábor...

Issue #3403337 by alexpott, quietone, Akhil Babu, vakulrai, smustgrave, Gábor Hojtsy, penyaskito, longwave, catch: The order of the projects coming from locale_translation_get_projects() is not consistent
parent 1e827843
Branches
Tags
32 merge requests!12227Issue #3181946 by jonmcl, mglaman,!11131[10.4.x-only-DO-NOT-MERGE]: Issue ##2842525 Ajax attached to Views exposed filter form does not trigger callbacks,!9470[10.3.x-only-DO-NOT-MERGE]: #3331771 Fix file_get_contents(): Passing null to parameter,!8540Issue #3457061: Bootstrap Modal dialog Not closing after 10.3.0 Update,!8528Issue #3456871 by Tim Bozeman: Support NULL services,!8373Issue #3427374 by danflanagan8, Vighneshh: taxonomy_tid ViewsArgumentDefault...,!7526Expose roles in response,!7352Draft: Resolve #3203489 "Set filename as",!5423Draft: Resolve #3329907 "Test2",!3878Removed unused condition head title for views,!3818Issue #2140179: $entity->original gets stale between updates,!3742Issue #3328429: Create item list field formatter for displaying ordered and unordered lists,!3731Claro: role=button on status report items,!3651Issue #3347736: Create new SDC component for Olivero (header-search),!3531Issue #3336994: StringFormatter always displays links to entity even if the user in context does not have access,!3478Issue #3337882: Deleted menus are not removed from content type config,!3355Issue #3209129: Scrolling problems when adding a block via layout builder,!3154Fixes #2987987 - CSRF token validation broken on routes with optional parameters.,!3133core/modules/system/css/components/hidden.module.css,!2964Issue #2865710 : Dependencies from only one instance of a widget are used in display modes,!2812Issue #3312049: [Followup] Fix Drupal.Commenting.FunctionComment.MissingReturnType returns for NULL,!2794Issue #3100732: Allow specifying `meta` data on JSON:API objects,!2378Issue #2875033: Optimize joins and table selection in SQL entity query implementation,!2062Issue #3246454: Add weekly granularity to views date sort,!1105Issue #3025039: New non translatable field on translatable content throws error,!1073issue #3191727: Focus states on mobile second level navigation items fixed,!10223132456: Fix issue where views instances are emptied before an ajax request is complete,!877Issue #2708101: Default value for link text is not saved,!579Issue #2230909: Simple decimals fail to pass validation,!560Move callback classRemove outside of the loop,!555Issue #3202493,!213Issue #2906496: Give Media a menu item under Content
Pipeline #112984 passed with warnings
Pipeline: drupal

#112987

    ......@@ -120,6 +120,9 @@ function hook_locale_translation_projects_alter(&$projects) {
    'info' => [
    'interface translation server pattern' => 'http://example.com/files/translations/%core/%project/%project-%version.%language.po',
    ],
    // An optional key to change the order in which translation files are
    // processed. By default, the projects are sorted alphabetically by key.
    'weight' => 1,
    ];
    }
    ......
    ......@@ -28,7 +28,14 @@ class LocaleProjectStorage implements LocaleProjectStorageInterface {
    *
    * @var bool
    */
    protected static $all = FALSE;
    protected bool $all = FALSE;
    /**
    * Sorted status flag.
    *
    * @var bool
    */
    protected bool $sorted = FALSE;
    /**
    * Constructs a State object.
    ......@@ -98,6 +105,7 @@ public function setMultiple(array $data) {
    $this->cache[$key] = $value;
    }
    $this->keyValueStore->setMultiple($data);
    $this->sorted = FALSE;
    }
    /**
    ......@@ -122,7 +130,7 @@ public function deleteMultiple(array $keys) {
    */
    public function resetCache() {
    $this->cache = [];
    static::$all = FALSE;
    $this->sorted = $this->all = FALSE;
    }
    /**
    ......@@ -159,11 +167,26 @@ public function countProjects() {
    * {@inheritdoc}
    */
    public function getAll() {
    if (!static::$all) {
    if (!$this->all) {
    $this->cache = $this->keyValueStore->getAll();
    static::$all = TRUE;
    }
    return $this->cache;
    $this->all = TRUE;
    }
    if (!$this->sorted) {
    // Work around PHP 8.3.0 - 8.3.3 bug by assigning $this->cache to a local
    // variable, see https://github.com/php/php-src/pull/13285.
    $cache = $this->cache;
    uksort($this->cache, function ($a, $b) use ($cache) {
    // Sort by weight, if available, and then by key. This allows locale
    // projects to set a weight, if required, and keeps the order consistent
    // regardless of whether the list is built from code or retrieve from
    // the database.
    $sort = (int) ($cache[$a]['weight'] ?? 0) <=> (int) ($cache[$b]['weight'] ?? 0);
    return $sort ?: strcmp($a, $b);
    });
    $this->sorted = TRUE;
    }
    // Remove any NULL values as these are not valid projects.
    return array_filter($this->cache, fn ($value) => $value !== NULL);
    }
    }
    <?php
    declare(strict_types=1);
    namespace Drupal\Tests\locale\Unit;
    use Drupal\Core\KeyValueStore\KeyValueMemoryFactory;
    use Drupal\locale\LocaleProjectStorage;
    use Drupal\Tests\UnitTestCase;
    /**
    * @coversDefaultClass \Drupal\locale\LocaleProjectStorage
    * @group locale
    * @runTestsInSeparateProcesses
    */
    class LocaleProjectStorageTest extends UnitTestCase {
    /**
    * @var \Drupal\locale\LocaleProjectStorage
    */
    private LocaleProjectStorage $projectStorage;
    /**
    * @var \Drupal\Core\KeyValueStore\KeyValueMemoryFactory
    */
    private KeyValueMemoryFactory $keyValueMemoryFactory;
    /**
    * {@inheritdoc}
    */
    protected function setUp(): void {
    parent::setUp();
    $this->keyValueMemoryFactory = new KeyValueMemoryFactory();
    $this->projectStorage = new LocaleProjectStorage($this->keyValueMemoryFactory);
    }
    /**
    * Tests that projects are sorted by weight and key.
    */
    public function testSorting(): void {
    // There are no projects.
    $this->assertSame([], $this->projectStorage->getAll());
    // Add project 'b'.
    $this->projectStorage->set('b', ['name' => 'b']);
    $this->assertSame(['b'], array_keys($this->projectStorage->getAll()));
    // Add project 'c' and confirm alphabetical order.
    $this->projectStorage->set('c', ['name' => 'c']);
    $this->assertSame(['b', 'c'], array_keys($this->projectStorage->getAll()));
    // Add project 'a' and confirm 'a' is first.
    $this->projectStorage->set('a', ['name' => 'a']);
    $this->assertSame(['a', 'b', 'c'], array_keys($this->projectStorage->getAll()));
    // Add project 'd' with a negative weight and confirm 'd' is first.
    $this->projectStorage->set('d', ['name' => 'd', 'weight' => -1]);
    $this->assertSame(['d', 'a', 'b', 'c'], array_keys($this->projectStorage->getAll()));
    // Add project 'aa' with a positive weight and confirm 'aa' is last.
    $this->projectStorage->set('aa', ['name' => 'aa', 'weight' => 1]);
    $this->assertSame(['d', 'a', 'b', 'c', 'aa'], array_keys($this->projectStorage->getAll()));
    // Delete project 'a'.
    $this->projectStorage->delete('a');
    $this->assertSame(['d', 'b', 'c', 'aa'], array_keys($this->projectStorage->getAll()));
    // Add project 'e' with a lower negative weight than 'd' and confirm 'e' is
    // first.
    $this->projectStorage->set('e', ['name' => 'e', 'weight' => -5]);
    $this->assertSame(['e', 'd', 'b', 'c', 'aa'], array_keys($this->projectStorage->getAll()));
    // Pretend there is a container rebuild by generating a new
    // LocaleProjectStorage object with the same data.
    $this->projectStorage = new LocaleProjectStorage($this->keyValueMemoryFactory);
    $this->projectStorage->set('z', ['name' => 'z']);
    $this->assertSame(['e', 'd', 'b', 'c', 'z', 'aa'], array_keys($this->projectStorage->getAll()));
    // Now delete all projects.
    $this->projectStorage->deleteAll();
    $this->assertSame([], $this->projectStorage->getAll());
    // Add project 'z' before project 'a' and confirm 'a' is first.
    $this->projectStorage->set('z', ['name' => 'z']);
    $this->projectStorage->set('a', ['name' => 'a']);
    $this->assertSame(['a', 'z'], array_keys($this->projectStorage->getAll()));
    }
    /**
    * Tests deleted projects are not included in the count.
    */
    public function testDelete(): void {
    $this->projectStorage->set('b', ['name' => 'b']);
    $this->assertSame(['name' => 'b'], $this->projectStorage->get('b'));
    $this->assertSame(1, $this->projectStorage->countProjects());
    $this->projectStorage->delete('b');
    $this->assertNull($this->projectStorage->get('b'));
    $this->assertSame(0, $this->projectStorage->countProjects());
    }
    }
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Please register or to comment