diff --git a/Classes/Service/UsageService.php b/Classes/Service/UsageService.php index 77b6f6bc..8a3eb6e2 100644 --- a/Classes/Service/UsageService.php +++ b/Classes/Service/UsageService.php @@ -70,14 +70,15 @@ public function formatNumber(int $number) // locale en or null, so we call with default parameter. $numberFormatter = new \NumberFormatter('en', \NumberFormatter::DECIMAL); } else { - $language = 'en'; + $language = 'default'; if ($this->getBackendUser() !== null) { $uc = $this->getBackendUser()->uc; if (is_array($uc) && array_key_exists('lang', $uc)) { $language = $uc['lang']; } } - $numberFormatter = new \NumberFormatter($language, \NumberFormatter::DECIMAL); + $locale = ($language !== 'default') ? $language : 'en'; + $numberFormatter = new \NumberFormatter($locale, \NumberFormatter::DECIMAL); } return $numberFormatter->format($number); } diff --git a/Tests/Functional/Services/Fixtures/Pages.csv b/Tests/Functional/Services/Fixtures/Pages.csv index 767adff1..f031ef84 100644 --- a/Tests/Functional/Services/Fixtures/Pages.csv +++ b/Tests/Functional/Services/Fixtures/Pages.csv @@ -5,3 +5,9 @@ pages,,,,, tt_content, ,uid,pid,header,CType,bodytext ,3,1,"DeepL-Functional-Test Element","text","" +"be_users" +,"uid","pid","tstamp","username","password","admin","disable","starttime","endtime","options","crdate","workspace_perms","deleted","TSconfig","lastlogin","workspace_id","uc" +# The password is "password" +# The user has a broken/outdated uc lang configuration. This is required testing the behaviour of #486 +,1,0,1366642540,"admin","$1$tCrlLajZ$C0sikFQQ3SWaFAZ1Me0Z/1",1,0,0,0,0,1366642540,1,0,,1371033743,0,"a:19:{s:10:""moduleData"";a:7:{s:28:""dashboard/current_dashboard/"";s:40:""764f4d1012c7b870a98ffd1e8dd3ff5e133cb451"";s:9:""scheduler"";a:1:{s:6:""action"";s:16:""scheduler_manage"";}s:13:""system_config"";a:1:{s:4:""tree"";s:3:""tca"";}s:10:""web_layout"";a:3:{s:8:""function"";s:1:""2"";s:8:""language"";s:1:""2"";s:10:""showHidden"";b:1;}s:10:""FormEngine"";a:2:{i:0;a:2:{s:32:""c31c3d00814edbf9b2ddab640af3f55d"";a:5:{i:0;s:116:""Bacon ipsum dolor sit strong amet capicola jerky pork chop rump shoulder shank. Shankle strip steak pig salami link."";i:1;a:5:{s:4:""edit"";a:1:{s:10:""tt_content"";a:1:{i:14;s:4:""edit"";}}s:7:""defVals"";N;s:12:""overrideVals"";N;s:11:""columnsOnly"";N;s:6:""noView"";N;}i:2;s:34:""&edit%5Btt_content%5D%5B14%5D=edit"";i:3;a:5:{s:5:""table"";s:10:""tt_content"";s:3:""uid"";i:14;s:3:""pid"";i:10;s:3:""cmd"";s:4:""edit"";s:12:""deleteAccess"";b:1;}i:4;s:99:""/typo3/module/web/layout?token=2fb2757ce2a0f7275162273a7363c3cdf5ae31e0&id=10#element-tt_content-14"";}s:32:""c312013d83c1a6ad7fec8b36a37ba3c8"";a:5:{i:0;s:25:""TYPO3 Styleguide Frontend"";i:1;a:5:{s:4:""edit"";a:1:{s:10:""tt_content"";a:1:{i:1;s:4:""edit"";}}s:7:""defVals"";N;s:12:""overrideVals"";N;s:11:""columnsOnly"";N;s:6:""noView"";N;}i:2;s:33:""&edit%5Btt_content%5D%5B1%5D=edit"";i:3;a:5:{s:5:""table"";s:10:""tt_content"";s:3:""uid"";i:1;s:3:""pid"";i:1;s:3:""cmd"";s:4:""edit"";s:12:""deleteAccess"";b:1;}i:4;s:98:""/typo3/module/web/layout?token=2fb2757ce2a0f7275162273a7363c3cdf5ae31e0&id=1&#element-tt_content-1"";}}i:1;s:32:""d63be24a7702dd6c8c0504bfe838a532"";}s:57:""TYPO3\CMS\Backend\Utility\BackendUtility::getUpdateSignal"";a:0:{}s:16:""opendocs::recent"";a:5:{s:32:""d63be24a7702dd6c8c0504bfe838a532"";a:5:{i:0;s:120:""Bacon ipsum dolor sit strong amet capicola jerky pork chop rump shoulder shank. Haxe Streifen Steak Schwein Salami Link."";i:1;a:5:{s:4:""edit"";a:1:{s:10:""tt_content"";a:1:{i:44;s:4:""edit"";}}s:7:""defVals"";N;s:12:""overrideVals"";N;s:11:""columnsOnly"";N;s:6:""noView"";N;}i:2;s:34:""&edit%5Btt_content%5D%5B44%5D=edit"";i:3;a:5:{s:5:""table"";s:10:""tt_content"";s:3:""uid"";i:44;s:3:""pid"";i:8;s:3:""cmd"";s:4:""edit"";s:12:""deleteAccess"";b:1;}i:4;s:99:""/typo3/module/web/layout?token=2fb2757ce2a0f7275162273a7363c3cdf5ae31e0&id=8&#element-tt_content-44"";}s:32:""ffbd6ae78a9aa555f88d6295c30fb80c"";a:5:{i:0;s:116:""Bacon ipsum dolor sit strong amet capicola jerky pork chop rump shoulder shank. Shankle strip steak pig salami link."";i:1;a:5:{s:4:""edit"";a:1:{s:10:""tt_content"";a:1:{i:10;s:4:""edit"";}}s:7:""defVals"";N;s:12:""overrideVals"";N;s:11:""columnsOnly"";N;s:6:""noView"";N;}i:2;s:34:""&edit%5Btt_content%5D%5B10%5D=edit"";i:3;a:5:{s:5:""table"";s:10:""tt_content"";s:3:""uid"";i:10;s:3:""pid"";i:8;s:3:""cmd"";s:4:""edit"";s:12:""deleteAccess"";b:1;}i:4;s:98:""/typo3/module/web/layout?token=2fb2757ce2a0f7275162273a7363c3cdf5ae31e0&id=8#element-tt_content-10"";}s:32:""f3a80bc04cdfd6ed305676c6deecde13"";a:5:{i:0;s:25:""TYPO3 Styleguide Frontend"";i:1;a:5:{s:4:""edit"";a:1:{s:10:""tt_content"";a:1:{i:43;s:4:""edit"";}}s:7:""defVals"";N;s:12:""overrideVals"";N;s:11:""columnsOnly"";N;s:6:""noView"";N;}i:2;s:34:""&edit%5Btt_content%5D%5B43%5D=edit"";i:3;a:5:{s:5:""table"";s:10:""tt_content"";s:3:""uid"";i:43;s:3:""pid"";i:1;s:3:""cmd"";s:4:""edit"";s:12:""deleteAccess"";b:1;}i:4;s:70:""/typo3/module/dashboard?token=dcec9d55204841dc643c2622b1dd11306044d7fa"";}s:32:""c312013d83c1a6ad7fec8b36a37ba3c8"";a:5:{i:0;s:25:""TYPO3 Styleguide Frontend"";i:1;a:5:{s:4:""edit"";a:1:{s:10:""tt_content"";a:1:{i:1;s:4:""edit"";}}s:7:""defVals"";N;s:12:""overrideVals"";N;s:11:""columnsOnly"";N;s:6:""noView"";N;}i:2;s:33:""&edit%5Btt_content%5D%5B1%5D=edit"";i:3;a:5:{s:5:""table"";s:10:""tt_content"";s:3:""uid"";i:1;s:3:""pid"";i:1;s:3:""cmd"";s:4:""edit"";s:12:""deleteAccess"";b:1;}i:4;s:97:""/typo3/module/web/layout?token=2fb2757ce2a0f7275162273a7363c3cdf5ae31e0&id=1#element-tt_content-1"";}s:32:""9b967901d6c9df7fbe10e9cd1eacc0fe"";a:5:{i:0;s:24:""styleguide frontend demo"";i:1;a:5:{s:4:""edit"";a:1:{s:5:""pages"";a:1:{i:1;s:4:""edit"";}}s:7:""defVals"";N;s:12:""overrideVals"";a:1:{s:5:""pages"";a:1:{s:16:""sys_language_uid"";s:1:""0"";}}s:11:""columnsOnly"";N;s:6:""noView"";N;}i:2;s:76:""&edit%5Bpages%5D%5B1%5D=edit&overrideVals%5Bpages%5D%5Bsys_language_uid%5D=0"";i:3;a:5:{s:5:""table"";s:5:""pages"";s:3:""uid"";i:1;s:3:""pid"";i:0;s:3:""cmd"";s:4:""edit"";s:12:""deleteAccess"";b:1;}i:4;s:217:""/typo3/record/edit?token=ae076486b94686606614f90d8a155ec1f785183e&edit%5Btt_content%5D%5B14%5D=edit&returnUrl=/typo3/module/web/layout?token%3D2fb2757ce2a0f7275162273a7363c3cdf5ae31e0%26id%3D10%23element-tt_content-14"";}}}s:14:""emailMeAtLogin"";i:0;s:8:""titleLen"";s:2:""50"";s:20:""edit_docModuleUpload"";i:1;s:15:""moduleSessionID"";a:7:{s:28:""dashboard/current_dashboard/"";s:40:""e47ba98e40d443d825f5d08a6545e37bbc86bac5"";s:9:""scheduler"";s:40:""e47ba98e40d443d825f5d08a6545e37bbc86bac5"";s:13:""system_config"";s:40:""e47ba98e40d443d825f5d08a6545e37bbc86bac5"";s:10:""web_layout"";s:40:""e47ba98e40d443d825f5d08a6545e37bbc86bac5"";s:10:""FormEngine"";s:40:""ac1694175250c17ad2c05ef590e41376512745be"";s:57:""TYPO3\CMS\Backend\Utility\BackendUtility::getUpdateSignal"";s:40:""75d90be2aa2bf0625bafeee69c3fdd82f726db12"";s:16:""opendocs::recent"";s:40:""ac1694175250c17ad2c05ef590e41376512745be"";}s:8:""realName"";s:0:"""";s:5:""email"";s:0:"""";s:8:""password"";s:0:"""";s:9:""password2"";s:0:"""";s:6:""avatar"";s:0:"""";s:4:""lang"";s:7:""default"";s:11:""startModule"";s:0:"""";s:25:""showHiddenFilesAndFolders"";i:0;s:10:""copyLevels"";s:0:"""";s:18:""resetConfiguration"";s:0:"""";s:12:""mfaProviders"";s:0:"""";s:18:""backendTitleFormat"";s:10:""titleFirst"";s:11:""colorScheme"";s:4:""auto"";s:5:""theme"";s:6:""modern"";}" +,2,0,1366642540,"admin2","$1$tCrlLajZ$C0sikFQQ3SWaFAZ1Me0Z/1",1,0,0,0,0,1366642540,1,0,,1371033743,0,"a:19:{s:10:""moduleData"";a:7:{s:28:""dashboard/current_dashboard/"";s:40:""764f4d1012c7b870a98ffd1e8dd3ff5e133cb451"";s:9:""scheduler"";a:1:{s:6:""action"";s:16:""scheduler_manage"";}s:13:""system_config"";a:1:{s:4:""tree"";s:3:""tca"";}s:10:""web_layout"";a:3:{s:8:""function"";s:1:""2"";s:8:""language"";s:1:""2"";s:10:""showHidden"";b:1;}s:10:""FormEngine"";a:2:{i:0;a:2:{s:32:""c31c3d00814edbf9b2ddab640af3f55d"";a:5:{i:0;s:116:""Bacon ipsum dolor sit strong amet capicola jerky pork chop rump shoulder shank. Shankle strip steak pig salami link."";i:1;a:5:{s:4:""edit"";a:1:{s:10:""tt_content"";a:1:{i:14;s:4:""edit"";}}s:7:""defVals"";N;s:12:""overrideVals"";N;s:11:""columnsOnly"";N;s:6:""noView"";N;}i:2;s:34:""&edit%5Btt_content%5D%5B14%5D=edit"";i:3;a:5:{s:5:""table"";s:10:""tt_content"";s:3:""uid"";i:14;s:3:""pid"";i:10;s:3:""cmd"";s:4:""edit"";s:12:""deleteAccess"";b:1;}i:4;s:99:""/typo3/module/web/layout?token=2fb2757ce2a0f7275162273a7363c3cdf5ae31e0&id=10#element-tt_content-14"";}s:32:""c312013d83c1a6ad7fec8b36a37ba3c8"";a:5:{i:0;s:25:""TYPO3 Styleguide Frontend"";i:1;a:5:{s:4:""edit"";a:1:{s:10:""tt_content"";a:1:{i:1;s:4:""edit"";}}s:7:""defVals"";N;s:12:""overrideVals"";N;s:11:""columnsOnly"";N;s:6:""noView"";N;}i:2;s:33:""&edit%5Btt_content%5D%5B1%5D=edit"";i:3;a:5:{s:5:""table"";s:10:""tt_content"";s:3:""uid"";i:1;s:3:""pid"";i:1;s:3:""cmd"";s:4:""edit"";s:12:""deleteAccess"";b:1;}i:4;s:98:""/typo3/module/web/layout?token=2fb2757ce2a0f7275162273a7363c3cdf5ae31e0&id=1&#element-tt_content-1"";}}i:1;s:32:""d63be24a7702dd6c8c0504bfe838a532"";}s:57:""TYPO3\CMS\Backend\Utility\BackendUtility::getUpdateSignal"";a:0:{}s:16:""opendocs::recent"";a:5:{s:32:""d63be24a7702dd6c8c0504bfe838a532"";a:5:{i:0;s:120:""Bacon ipsum dolor sit strong amet capicola jerky pork chop rump shoulder shank. Haxe Streifen Steak Schwein Salami Link."";i:1;a:5:{s:4:""edit"";a:1:{s:10:""tt_content"";a:1:{i:44;s:4:""edit"";}}s:7:""defVals"";N;s:12:""overrideVals"";N;s:11:""columnsOnly"";N;s:6:""noView"";N;}i:2;s:34:""&edit%5Btt_content%5D%5B44%5D=edit"";i:3;a:5:{s:5:""table"";s:10:""tt_content"";s:3:""uid"";i:44;s:3:""pid"";i:8;s:3:""cmd"";s:4:""edit"";s:12:""deleteAccess"";b:1;}i:4;s:99:""/typo3/module/web/layout?token=2fb2757ce2a0f7275162273a7363c3cdf5ae31e0&id=8&#element-tt_content-44"";}s:32:""ffbd6ae78a9aa555f88d6295c30fb80c"";a:5:{i:0;s:116:""Bacon ipsum dolor sit strong amet capicola jerky pork chop rump shoulder shank. Shankle strip steak pig salami link."";i:1;a:5:{s:4:""edit"";a:1:{s:10:""tt_content"";a:1:{i:10;s:4:""edit"";}}s:7:""defVals"";N;s:12:""overrideVals"";N;s:11:""columnsOnly"";N;s:6:""noView"";N;}i:2;s:34:""&edit%5Btt_content%5D%5B10%5D=edit"";i:3;a:5:{s:5:""table"";s:10:""tt_content"";s:3:""uid"";i:10;s:3:""pid"";i:8;s:3:""cmd"";s:4:""edit"";s:12:""deleteAccess"";b:1;}i:4;s:98:""/typo3/module/web/layout?token=2fb2757ce2a0f7275162273a7363c3cdf5ae31e0&id=8#element-tt_content-10"";}s:32:""f3a80bc04cdfd6ed305676c6deecde13"";a:5:{i:0;s:25:""TYPO3 Styleguide Frontend"";i:1;a:5:{s:4:""edit"";a:1:{s:10:""tt_content"";a:1:{i:43;s:4:""edit"";}}s:7:""defVals"";N;s:12:""overrideVals"";N;s:11:""columnsOnly"";N;s:6:""noView"";N;}i:2;s:34:""&edit%5Btt_content%5D%5B43%5D=edit"";i:3;a:5:{s:5:""table"";s:10:""tt_content"";s:3:""uid"";i:43;s:3:""pid"";i:1;s:3:""cmd"";s:4:""edit"";s:12:""deleteAccess"";b:1;}i:4;s:70:""/typo3/module/dashboard?token=dcec9d55204841dc643c2622b1dd11306044d7fa"";}s:32:""c312013d83c1a6ad7fec8b36a37ba3c8"";a:5:{i:0;s:25:""TYPO3 Styleguide Frontend"";i:1;a:5:{s:4:""edit"";a:1:{s:10:""tt_content"";a:1:{i:1;s:4:""edit"";}}s:7:""defVals"";N;s:12:""overrideVals"";N;s:11:""columnsOnly"";N;s:6:""noView"";N;}i:2;s:33:""&edit%5Btt_content%5D%5B1%5D=edit"";i:3;a:5:{s:5:""table"";s:10:""tt_content"";s:3:""uid"";i:1;s:3:""pid"";i:1;s:3:""cmd"";s:4:""edit"";s:12:""deleteAccess"";b:1;}i:4;s:97:""/typo3/module/web/layout?token=2fb2757ce2a0f7275162273a7363c3cdf5ae31e0&id=1#element-tt_content-1"";}s:32:""9b967901d6c9df7fbe10e9cd1eacc0fe"";a:5:{i:0;s:24:""styleguide frontend demo"";i:1;a:5:{s:4:""edit"";a:1:{s:5:""pages"";a:1:{i:1;s:4:""edit"";}}s:7:""defVals"";N;s:12:""overrideVals"";a:1:{s:5:""pages"";a:1:{s:16:""sys_language_uid"";s:1:""0"";}}s:11:""columnsOnly"";N;s:6:""noView"";N;}i:2;s:76:""&edit%5Bpages%5D%5B1%5D=edit&overrideVals%5Bpages%5D%5Bsys_language_uid%5D=0"";i:3;a:5:{s:5:""table"";s:5:""pages"";s:3:""uid"";i:1;s:3:""pid"";i:0;s:3:""cmd"";s:4:""edit"";s:12:""deleteAccess"";b:1;}i:4;s:217:""/typo3/record/edit?token=ae076486b94686606614f90d8a155ec1f785183e&edit%5Btt_content%5D%5B14%5D=edit&returnUrl=/typo3/module/web/layout?token%3D2fb2757ce2a0f7275162273a7363c3cdf5ae31e0%26id%3D10%23element-tt_content-14"";}}}s:14:""emailMeAtLogin"";i:0;s:8:""titleLen"";s:2:""50"";s:20:""edit_docModuleUpload"";i:1;s:15:""moduleSessionID"";a:7:{s:28:""dashboard/current_dashboard/"";s:40:""e47ba98e40d443d825f5d08a6545e37bbc86bac5"";s:9:""scheduler"";s:40:""e47ba98e40d443d825f5d08a6545e37bbc86bac5"";s:13:""system_config"";s:40:""e47ba98e40d443d825f5d08a6545e37bbc86bac5"";s:10:""web_layout"";s:40:""e47ba98e40d443d825f5d08a6545e37bbc86bac5"";s:10:""FormEngine"";s:40:""ac1694175250c17ad2c05ef590e41376512745be"";s:57:""TYPO3\CMS\Backend\Utility\BackendUtility::getUpdateSignal"";s:40:""75d90be2aa2bf0625bafeee69c3fdd82f726db12"";s:16:""opendocs::recent"";s:40:""ac1694175250c17ad2c05ef590e41376512745be"";}s:8:""realName"";s:0:"""";s:5:""email"";s:0:"""";s:8:""password"";s:0:"""";s:9:""password2"";s:0:"""";s:6:""avatar"";s:0:"""";s:4:""lang"";s:2:""de"";s:11:""startModule"";s:0:"""";s:25:""showHiddenFilesAndFolders"";i:0;s:10:""copyLevels"";s:0:"""";s:18:""resetConfiguration"";s:0:"""";s:12:""mfaProviders"";s:0:"""";s:18:""backendTitleFormat"";s:10:""titleFirst"";s:11:""colorScheme"";s:4:""auto"";s:5:""theme"";s:6:""modern"";}" diff --git a/Tests/Functional/Services/UsageServiceTest.php b/Tests/Functional/Services/UsageServiceTest.php index f4181770..d1b34ffc 100644 --- a/Tests/Functional/Services/UsageServiceTest.php +++ b/Tests/Functional/Services/UsageServiceTest.php @@ -6,6 +6,7 @@ use DeepL\Usage; use DeepL\UsageDetail; +use TYPO3\CMS\Core\Information\Typo3Version; use WebVision\WvDeepltranslate\Service\DeeplService; use WebVision\WvDeepltranslate\Service\ProcessingInstruction; use WebVision\WvDeepltranslate\Service\UsageService; @@ -113,4 +114,44 @@ public function checkHTMLMarkupsIsNotPartOfLimit(): void static::assertInstanceOf(UsageDetail::class, $character); static::assertEquals(strlen($translateContent), $character->count); } + + public static function numberFormatterLocalesDataProvider(): \Generator + { + yield 'Default formats to english' => [ + 'user' => 1, + 'number' => 20000, + 'expectedFormat' => '20,000', + ]; + yield 'BE uc lang "de" formats german' => [ + 'user' => 2, + 'number' => 93254850, + 'expectedFormat' => '93.254.850', + ]; + } + /** + * This test ensures that in PHP >=8.4 the NumberFormatter works correctly. + * With migrated TYPO3 data there is the possibility that uc['lang'] is set to 'default', + * which is no correct format for a locale the number formatter accepts. THis will lead + * to an error during initialisation. + * + * @test + * @dataProvider numberFormatterLocalesDataProvider + */ + public function numberFormatRespectsLocalesAndDefault( + int $user, + int $number, + string $expectedFormat + ): void { + // TYPO3 v11 seems not to respect the UC language setting, if other than default. skip this test for user 2 + if ((new Typo3Version())->getMajorVersion() <= 11 && $user === 2) { + static::markTestSkipped('The issue only appears in PHP 8.4, which is not supported with TYPO3 11'); + } + $this->importCSVDataSet(__DIR__ . '/Fixtures/Pages.csv'); + $this->setUpBackendUser($user); + /** @var UsageService $usageService */ + $usageService = $this->get(UsageService::class); + + $formatted = $usageService->formatNumber($number); + static::assertEquals($expectedFormat, $formatted); + } }