Files
XC_VM/tests/Unit/TranslatorTest.php
T
Divarion_D c370dc47fc test(core): cover FileCache and the Translator backfill
Fourth coverage batch — file-backed cache and i18n, each driven against a
throwaway temp directory:

- FileCacheTest: set/get roundtrip through serialization, miss = false, has(),
  idempotent delete, flush, maxAge expiry (backdated mtime), and the path/age
  accessors.
- TranslatorTest: English default, cookie language detection with fallback,
  available() listing, {token} substitution, guarded setLanguage(), and the
  hardened backfill — a key missing from the active language is written back
  with the English value, or with itself as a visible placeholder when English
  has none either.

+15 tests. Suite: 661 tests, 0 errors.
2026-09-13 14:45:12 +03:00

93 lines
3.1 KiB
PHP

<?php
use XcVm\Core\Localization\Translator;
use PHPUnit\Framework\TestCase;
/**
* Translator — INI-backed i18n with automatic backfill. Drives it against a
* throwaway langs directory (en.ini + a partial ru.ini) to cover language
* detection/switching, placeholder substitution, and the key behaviour it was
* hardened for: a missing key is copied into the active language file (English
* value, or the key itself as a visible placeholder) so translators can see
* what still needs work.
*/
final class TranslatorTest extends TestCase {
private string $dir;
protected function setUp(): void {
$this->dir = sys_get_temp_dir() . '/xcvm_i18n_' . uniqid('', true);
mkdir($this->dir, 0755, true);
file_put_contents($this->dir . '/en.ini', "greeting = \"Hello\"\nname = \"Name\"\nwelcome = \"Hi {n}\"\n");
file_put_contents($this->dir . '/ru.ini', "greeting = \"Привет\"\n");
unset($_COOKIE['lang']);
}
protected function tearDown(): void {
foreach (glob($this->dir . '/*') ?: [] as $f) {
unlink($f);
}
@rmdir($this->dir);
unset($_COOKIE['lang']);
}
public function testDefaultsToEnglishAndReadsValues(): void {
Translator::init($this->dir);
$this->assertSame('en', Translator::current());
$this->assertSame('Hello', Translator::get('greeting'));
}
public function testDetectsLanguageFromCookie(): void {
$_COOKIE['lang'] = 'ru';
Translator::init($this->dir);
$this->assertSame('ru', Translator::current());
$this->assertSame('Привет', Translator::get('greeting'));
}
public function testUnknownCookieLanguageFallsBackToEnglish(): void {
$_COOKIE['lang'] = 'zz';
Translator::init($this->dir);
$this->assertSame('en', Translator::current());
}
public function testAvailableListsEveryIniFile(): void {
Translator::init($this->dir);
$available = Translator::available();
sort($available);
$this->assertSame(['en', 'ru'], $available);
}
public function testGetAppliesReplacements(): void {
Translator::init($this->dir);
$this->assertSame('Hi Bob', Translator::get('welcome', ['{n}' => 'Bob']));
}
public function testSetLanguageSwitchesOnlyToKnownLanguages(): void {
Translator::init($this->dir);
$this->assertFalse(Translator::setLanguage('zz'));
$this->assertTrue(Translator::setLanguage('ru'));
$this->assertSame('ru', Translator::current());
}
public function testMissingKeyBackfillsEnglishValueIntoActiveLanguage(): void {
$_COOKIE['lang'] = 'ru';
Translator::init($this->dir);
// 'name' exists in en.ini but not ru.ini → returns the English source
$this->assertSame('Name', Translator::get('name'));
// ...and is appended to ru.ini so the gap is visible to translators.
$ru = file_get_contents($this->dir . '/ru.ini');
$this->assertStringContainsString('name = "Name"', $ru);
}
public function testUnknownKeyBackfillsItselfAsPlaceholder(): void {
Translator::init($this->dir);
$this->assertSame('totally_new_key', Translator::get('totally_new_key'));
$en = file_get_contents($this->dir . '/en.ini');
$this->assertStringContainsString('totally_new_key = "totally_new_key"', $en);
}
}