From 2c4dd2594cc47ca0b5cd719b963304ec48aecba2 Mon Sep 17 00:00:00 2001 From: rugk Date: Thu, 13 Nov 2025 10:52:08 +0000 Subject: [PATCH] fix: do not encode source JSON translation string resulting in wrong display of special characters like ' Fixes #1712 Disclosure: Coded with help of Copiot. (description wrtten by me) So this does indeed loosen the encoding a bit. However, IMHO, it was neither better before though. You could always bypass the encoding for `args{0]` when you just include `')) { - continue; - } - } elseif (is_int($args[$i])) { + for ($i = 1; $i < $argsCount; ++$i) { + if (is_int($args[$i])) { continue; } $args[$i] = self::encode($args[$i]); diff --git a/tst/I18nTest.php b/tst/I18nTest.php index 9e196103..118fe23b 100644 --- a/tst/I18nTest.php +++ b/tst/I18nTest.php @@ -182,7 +182,20 @@ class I18nTest extends TestCase $result = htmlspecialchars($input, ENT_QUOTES | ENT_HTML5 | ENT_DISALLOWED, 'UTF-8', false); $this->assertEquals($result, I18n::encode($input), 'encodes HTML entities'); $this->assertEquals('some ' . $result . ' + 1', I18n::_('some %s + %d', $input, 1), 'encodes parameters in translations'); - $this->assertEquals($result . $result, I18n::_($input . '%s', $input), 'encodes message ID as well, when no link'); + // Message ID should NOT be encoded (it comes from trusted source), only the parameter should be + $this->assertEquals($input . $result, I18n::_($input . '%s', $input), 'encodes only parameters, not message ID'); + } + + public function testFrenchApostropheInMessage() + { + $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'fr'; + I18n::loadTranslations(); + // The French translation should not have the apostrophe encoded + // Original: "Le document n'existe pas, a expiré, ou a été supprimé." + // Should NOT become: "Le document n'existe pas, a expiré, ou a été supprimé." + $message = I18n::_('Document does not exist, has expired or has been deleted.'); + $this->assertFalse(strpos($message, ''') !== false, 'French apostrophe should not be encoded in translation message'); + $this->assertTrue(strpos($message, "n'existe") !== false, 'French apostrophe should be present as literal character'); } public function testFallbackAlwaysPresent()