diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a66ba365c..beb04ec3ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,7 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Deprecated -- Nothing +- Functions `_translateFormulaToLocale` and `_translateFormulaEnglish` are replaced by versions without leading underscore. [PR #3828](https://github.com/PHPOffice/PhpSpreadsheet/pull/3828) ### Removed @@ -78,6 +78,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Html omitting some charts. [Issue #3767](https://github.com/PHPOffice/PhpSpreadsheet/issues/3767) [PR #3771](https://github.com/PHPOffice/PhpSpreadsheet/pull/3771) - Case Insensitive Comparison for Sheet Names [PR #3791](https://github.com/PHPOffice/PhpSpreadsheet/pull/3791) - Performance improvement for Xlsx Reader. [Issue #3683](https://github.com/PHPOffice/PhpSpreadsheet/issues/3683) [PR #3810](https://github.com/PHPOffice/PhpSpreadsheet/pull/3810) +- Strip `xlfn.` and `xlws.` from Formula Translations. [Issue #3819](https://github.com/PHPOffice/PhpSpreadsheet/issues/3819) [PR #3828](https://github.com/PHPOffice/PhpSpreadsheet/pull/3828) - Prevent loop in Shared/File. [Issue #3807](https://github.com/PHPOffice/PhpSpreadsheet/issues/3807) [PR #3809](https://github.com/PHPOffice/PhpSpreadsheet/pull/3809) - Consistent handling of decimal/thousands separators between StringHelper and Php setlocale. [Issue #3811](https://github.com/PHPOffice/PhpSpreadsheet/issues/3811) [PR #3815](https://github.com/PHPOffice/PhpSpreadsheet/pull/3815) - Clone worksheet with tables or charts. [Issue #3820](https://github.com/PHPOffice/PhpSpreadsheet/issues/3820) [PR #3821](https://github.com/PHPOffice/PhpSpreadsheet/pull/3821) diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 960db939c2..03800f08de 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -34,6 +34,8 @@ class Calculation const CALCULATION_REGEXP_OPENBRACE = '\('; // Function (allow for the old @ symbol that could be used to prefix a function, but we'll ignore it) const CALCULATION_REGEXP_FUNCTION = '@?(?:_xlfn\.)?(?:_xlws\.)?([\p{L}][\p{L}\p{N}\.]*)[\s]*\('; + // Strip xlfn and xlws prefixes from function name + const CALCULATION_REGEXP_STRIP_XLFN_XLWS = '/(_xlfn[.])?(_xlws[.])?(?=[\p{L}][\p{L}\p{N}\.]*[\s]*[(])/'; // Cell reference (cell or range of cells, with or without a sheet reference) const CALCULATION_REGEXP_CELLREF = '((([^\s,!&%^\/\*\+<>=:`-]*)|(\'(?:[^\']|\'[^!])+?\')|(\"(?:[^\"]|\"[^!])+?\"))!)?\$?\b([a-z]{1,3})\$?(\d{1,7})(?![\w.])'; // Cell reference (with or without a sheet reference) ensuring absolute/relative @@ -3326,8 +3328,19 @@ private static function translateFormula(array $from, array $to, string $formula /** @var ?array */ private static $functionReplaceToLocale; + /** + * @deprecated 1.30.0 use translateFormulaToLocale() instead + * + * @codeCoverageIgnore + */ public function _translateFormulaToLocale(string $formula): string { + return $this->translateFormulaToLocale($formula); + } + + public function translateFormulaToLocale(string $formula): string + { + $formula = preg_replace(self::CALCULATION_REGEXP_STRIP_XLFN_XLWS, '', $formula) ?? ''; // Build list of function names and constants for translation if (self::$functionReplaceFromExcel === null) { self::$functionReplaceFromExcel = []; @@ -3364,7 +3377,17 @@ public function _translateFormulaToLocale(string $formula): string /** @var ?array */ private static $functionReplaceToExcel; + /** + * @deprecated 1.30.0 use translateFormulaToEnglish() instead + * + * @codeCoverageIgnore + */ public function _translateFormulaToEnglish(string $formula): string + { + return $this->translateFormulaToEnglish($formula); + } + + public function translateFormulaToEnglish(string $formula): string { if (self::$functionReplaceFromLocale === null) { self::$functionReplaceFromLocale = []; diff --git a/tests/PhpSpreadsheetTests/Calculation/TranslationTest.php b/tests/PhpSpreadsheetTests/Calculation/TranslationTest.php index c14ee0a64a..ec9a2acaf7 100644 --- a/tests/PhpSpreadsheetTests/Calculation/TranslationTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/TranslationTest.php @@ -47,7 +47,7 @@ public function testTranslation(string $expectedResult, string $locale, string $ self::assertSame($expectedResult, $translatedFormula); $restoredFormula = Calculation::getInstance()->_translateFormulaToEnglish($translatedFormula); - self::assertSame($formula, $restoredFormula); + self::assertSame(preg_replace(Calculation::CALCULATION_REGEXP_STRIP_XLFN_XLWS, '', $formula), $restoredFormula); } public static function providerTranslations(): array diff --git a/tests/data/Calculation/Translations.php b/tests/data/Calculation/Translations.php index b0849ff274..ce5370f392 100644 --- a/tests/data/Calculation/Translations.php +++ b/tests/data/Calculation/Translations.php @@ -92,4 +92,24 @@ 'fr', '=3*ROW(B1)', ], + 'handle _xlfn' => [ + '=MAXWENNS(C5:C10; C5:C10; "<30")', + 'de', + '=_xlfn.MAXIFS(C5:C10, C5:C10, "<30")', + ], + 'handle _xlfn and _xlws' => [ + '=ФИЛЬТР(A5:D20;C5:C20=H2;"")', + 'ru', + '=_xlfn._xlws.FILTER(A5:D20,C5:C20=H2,"")', + ], + 'implicit intersection' => [ + '=@INDEKS(A1:A10;B1)', + 'nb', + '=@INDEX(A1:A10,B1)', + ], + 'preserve literal _xlfn.' => [ + '=@INDEKS(A1:A10;"_xlfn.")', + 'nb', + '=@INDEX(A1:A10,"_xlfn.")', + ], ];