{"record":{"id":"6465c5fb5b28fe7a","repo":"PHPOffice/PhpSpreadsheet","slug":"the-intl-extension-does-not-support-accounting-for","errorCode":null,"errorMessage":"The Intl extension does not support Accounting Formats without ICU 53","messagePattern":"The Intl extension does not support Accounting Formats without ICU 53","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Style/NumberFormat/Wizard/Accounting.php","lineNumber":21,"sourceCode":"namespace PhpOffice\\PhpSpreadsheet\\Style\\NumberFormat\\Wizard;\n\nuse NumberFormatter;\nuse PhpOffice\\PhpSpreadsheet\\Exception;\n\nclass Accounting extends CurrencyBase\n{\n    protected ?bool $overrideSpacing = true;\n\n    protected ?CurrencyNegative $overrideNegative = CurrencyNegative::parentheses;\n\n    /**\n     * @throws Exception if the Intl extension and ICU version don't support Accounting formats\n     */\n    protected function getLocaleFormat(): string\n    {\n        if (self::icuVersion() < 53.0) {\n            // @codeCoverageIgnoreStart\n            throw new Exception('The Intl extension does not support Accounting Formats without ICU 53');\n            // @codeCoverageIgnoreEnd\n        }\n\n        // Scrutinizer does not recognize CURRENCY_ACCOUNTING\n        $formatter = new Locale($this->fullLocale, NumberFormatter::CURRENCY_ACCOUNTING);\n        $mask = $formatter->format($this->stripLeadingRLM);\n        if ($this->decimals === 0) {\n            $mask = (string) preg_replace('/\\.0+/miu', '', $mask);\n        }\n\n        return str_replace('¤', $this->formatCurrencyCode(), $mask);\n    }\n\n    public static function icuVersion(): float\n    {\n        [$major, $minor] = explode('.', INTL_ICU_VERSION);\n\n        return (float) \"{$major}.{$minor}\";","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Style/NumberFormat/Wizard/Accounting.php#L3-L39","documentation":"Thrown by the Accounting number-format Wizard when a locale-aware accounting mask is requested but the installed ICU library is older than version 53. Accounting formats rely on NumberFormatter::CURRENCY_ACCOUNTING, which ICU only supports from 53 onwards, so getLocaleFormat() refuses to run rather than emit a wrong mask. It fires only when the intl extension reports an ICU version below 53.0, which is rare on current PHP builds.","triggerScenarios":"Calling (new Accounting(2, '€', 'de-DE'))->format(), or any Accounting wizard with a non-empty locale, on a PHP build whose intl extension links ICU < 53 (checked via INTL_ICU_VERSION).","commonSituations":"Legacy hosting, old Ubuntu/Debian PHP packages, outdated XAMPP/WAMP bundles, or containers built from very old base images where PHP was upgraded but the ICU library was not.","solutions":["Upgrade PHP/intl so it links ICU >= 53 (verify with `echo INTL_ICU_VERSION;`), usually via current distro or sury/ondrej-php packages","Build the accounting format without a locale so the wizard uses its built-in mask (pass '' as the locale argument)","Catch the exception and fall back to a hand-written format code such as '_-\"€\"* #,##0.00_-;-\"€\"* #,##0.00_-;_-\"€\"* \"-\"??_-;_-@_-'"],"exampleFix":"// before\n$mask = (new Accounting(2, '€', 'de-DE'))->format();\n\n// after (guard for old ICU)\nif (defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '53.0', '>=')) {\n    $mask = (new Accounting(2, '€', 'de-DE'))->format();\n} else {\n    $mask = '_-\"€\"* #,##0.00_-;-\"€\"* #,##0.00_-;_-\"€\"* \"-\"??_-;_-@_-';\n}","handlingStrategy":"validation","validationCode":"$icuOk = extension_loaded('intl') && defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '53.0', '>=');\nif ($icuOk) {\n    $mask = (new Accounting(2, '€', 'de-DE'))->format();\n} else {\n    $mask = '_-\"€\"* #,##0.00_-;-\"€\"* #,##0.00_-;_-\"€\"* \"-\"??_-;_-@_-';\n}","typeGuard":"function icuSupportsAccountingFormats(): bool\n{\n    return extension_loaded('intl')\n        && defined('INTL_ICU_VERSION')\n        && version_compare(INTL_ICU_VERSION, '53.0', '>=');\n}","tryCatchPattern":"try {\n    $mask = $accountingWizard->format();\n} catch (\\PhpOffice\\PhpSpreadsheet\\Exception $e) {\n    // ICU too old: fall back to a hardcoded accounting format code\n    $mask = '_-\"€\"* #,##0.00_-;-\"€\"* #,##0.00_-;_-\"€\"* \"-\"??_-;_-@_-';\n}","preventionTips":["Print INTL_ICU_VERSION in your CI to catch old ICU builds before release","Pin base images/Docker stages that bundle a current ICU","Avoid locale-driven wizards unless the deployment environment is known"],"tags":["intl","icu","accounting-format","locale","number-format","phpspreadsheet"],"backgroundTag":"icu-version-too-low","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}