`Extend\Locales` translations never register in integration tests (1.x + 2.x)
- Dominant language
- PHP
- Stars
- 6.7k
- Forks
- 883
- Avg merge
- 15h 16m
- Merged PRs (30d)
- 73
Description
### What's happening
When writing an integration test for an extension that ships with locale files via `Extend\Locales`, translation keys from the extension's own `resources/locale/*.yml` are never loaded into the catalogue. Calls like `$translator->get('my-ext.some.key')` just echo the key back.
### Reproduction
In an extension's integration test:
```php
public function setUp(): void
{
parent::setUp();
$this->extension('my-vendor-myext');
}
/** @test */
public function extension_translations_are_loaded()
{
$translator = $this->app()->getContainer()->make(
\Illuminate\Contracts\Translation\Translator::class
);
// Fails: returns 'my-vendor-myext.some.key' instead of the translated value
$this->assertNotEquals(
'my-vendor-myext.some.key',
$translator->get('my-vendor-myext.some.key')
);
}
```
Core translations (`flarum.*`, `validation.*`) work fine because they're registered directly by `LocaleServiceProvider` at the time `LocaleManager` is constructed.
### Root cause
`Extend\Locales::extend()` registers translation loading via `$container->resolving(LocaleManager::class, …)` — a callback that only fires when the container *resolves* the `LocaleManager` singleton. Because `LocaleManager` is a singleton, it is resolved exactly once.
The test harness calls `ExtensionManager::enable($id)` before `ExtensionManager::extend($container)` (see [`OverrideExtensionManagerForTests`](https://github.com/flarum/framework/blob/2.x/php-packages/testing/src/integration/Extend/OverrideExtensionManagerForTests.php#L34-L44)):
```php
foreach ($this->extensions as $extension) {
$extensionManager->enable($extension); // fires Locales::onEnable → make(LocaleManager::class) → singleton resolved NOW
}
$extensionManager->booted = true;
$extensionManager->extend($container); // only now is Locales::extend() called, but the resolving() callback arrives too late
```
`Locales::onEnable()` calls `$container->make(LocaleManager::class)->clearCache()`, which triggers the first resolution of the singleton — *before* `Locales::extend()` has had a chance to register its `resolving()` callback. From that point on, the callback can never fire.
In production, this ordering is not a problem because `LocaleManager` is resolved lazily at HTTP request time — well after all extenders have registered their `resolving()` hooks during the normal boot flow.
### Impact
- Any integration test that exercises code which calls into the extension's translator returns raw translation keys
- Silently produces misleading test output (e.g. a `Subject:` in a sent email containing `my-ext.email.default_subject` instead of the translated string) rather than failing noisily
- Affects both 1.x and 2.x — identical ordering in both `OverrideExtensionManagerForTests` implementations
### Current workaround in test
```php
$locales = $this->app()->getContainer()->make(\Flarum\Locale\LocaleManager::class);
$locales->addTranslations('en', __DIR__.'/../../resources/locale/en.yml');
$locales->clearCache();
```
### Suggested fix
Simplest surgical change: swap the two calls in `OverrideExtensionManagerForTests::extend()`:
```php
$extensionManager->booted = true;
$extensionManager->extend($container); // apply extenders first — Locales registers its resolving() callback
foreach ($this->extensions as $extension) {
$extensionManager->enable($extension); // now safe — when onEnable resolves LocaleManager, the callback fires
}
```
Need to verify this doesn't break other lifecycle assumptions (e.g. migrations running before extenders are applied), but given the current order already leads to broken locale loading, the extender-first approach aligns better with production boot sequencing.
### Environment
- Reproduced on Flarum 1.8 (testing 1.8)
- Same ordering confirmed present in [2.x](https://github.com/flarum/framework/blob/2.x/php-packages/testing/src/integration/Extend/OverrideExtensionManagerForTests.php#L34-L44)
Contributor guide
Assessment
This issue has not been assessed yet.