@rowsncolumns/fast-formula-parser 6.2.45 → 6.2.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +643 -35
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +643 -35
- package/dist/esm/index.js.map +1 -1
- package/package.json +2 -2
package/dist/esm/index.js
CHANGED
|
@@ -701,7 +701,9 @@ const excelNumberPrePass = (pattern, value, l10n, render) => {
|
|
|
701
701
|
if (!info)
|
|
702
702
|
return { value };
|
|
703
703
|
if (info.kind === "date") {
|
|
704
|
-
|
|
704
|
+
// A negative date or time — an elapsed `[h]:mm` duration included —
|
|
705
|
+
// shows `#######` in Excel's 1900 date system.
|
|
706
|
+
if (info.isElapsed && sections.length === 1 && value >= 0)
|
|
705
707
|
return { value };
|
|
706
708
|
if (value < 0 || value >= MAX_DATE_SERIAL_EXCLUSIVE) {
|
|
707
709
|
return { text: DATE_OVERFLOW_DISPLAY, value };
|
|
@@ -716,6 +718,16 @@ const excelNumberPrePass = (pattern, value, l10n, render) => {
|
|
|
716
718
|
if (index === 1 && value < 0 && pre.text === undefined && pre.value === 0) {
|
|
717
719
|
return { text: render(sections[index], 0), value };
|
|
718
720
|
}
|
|
721
|
+
// A one-section format keeps the minus of a negative that rounds to zero:
|
|
722
|
+
// Excel shows -0.4 in `0` as `-0` (and -0.004 in `0.00` as `-0.00`).
|
|
723
|
+
if (index === 0 &&
|
|
724
|
+
implicitSign &&
|
|
725
|
+
value < 0 &&
|
|
726
|
+
info.kind === "number" &&
|
|
727
|
+
pre.text === undefined &&
|
|
728
|
+
pre.value === 0) {
|
|
729
|
+
return { text: `-${render(sections[0], 0)}`, value };
|
|
730
|
+
}
|
|
719
731
|
return pre;
|
|
720
732
|
};
|
|
721
733
|
|
|
@@ -3801,6 +3813,500 @@ function isDateFormat (pattern) {
|
|
|
3801
3813
|
return isDate(data.partitions);
|
|
3802
3814
|
}
|
|
3803
3815
|
|
|
3816
|
+
/**
|
|
3817
|
+
* East Asian number-format tokens `numfmt` does not render: the `[DBNum1]`–`[DBNum4]` numeral
|
|
3818
|
+
* systems, the Japanese emperor-era tokens (`g`/`gg`/`ggg`, and `e`/`ee` under a Japanese locale)
|
|
3819
|
+
* and the `aaa`/`aaaa` weekday tokens. TypeScript twin of the engine's Rust
|
|
3820
|
+
* `rnc-cellmodel/src/cjk_format.rs` — keep the two in step.
|
|
3821
|
+
*
|
|
3822
|
+
* {@link prepareCjkNumberFormat} rewrites a format code so the base formatter can render it (era
|
|
3823
|
+
* names, era years and weekday names become quoted literals computed from the date serial,
|
|
3824
|
+
* `[DBNumN]` is removed, and under `[DBNumN]` a date's year becomes a quoted literal in that numeral
|
|
3825
|
+
* system); `finish` then turns the remaining ASCII digits into the numeral system:
|
|
3826
|
+
*
|
|
3827
|
+
* - `General` and date fields read as a number with units (`123` → `百二十三`, `15日` → `十五日`);
|
|
3828
|
+
* - digit placeholders (`0`, `#`) and years read digit by digit (`[DBNum1]0` → `一二三`).
|
|
3829
|
+
*
|
|
3830
|
+
* The language comes from the code's `[$-LCID]` / `[$-tag]` token, then the workbook locale, and
|
|
3831
|
+
* defaults to Japanese.
|
|
3832
|
+
*/
|
|
3833
|
+
const DBNUM_TOKEN = /^\[dbnum([1-4])\]$/i;
|
|
3834
|
+
/** Cheap pre-filter: a `DBNum` token, a `g` (era name or `General`), `aaa`, or an `e` beside a locale token. */
|
|
3835
|
+
const mightContainTokens = (code) => /[gG]|dbnum|aaa/i.test(code) || (/[eE]/.test(code) && code.includes("[$"));
|
|
3836
|
+
const prepareCjkNumberFormat = (code, value, workbookLocale) => {
|
|
3837
|
+
if (!mightContainTokens(code))
|
|
3838
|
+
return undefined;
|
|
3839
|
+
const tag = localeTag(code);
|
|
3840
|
+
const tagLang = tag ? cjkLangOfTag(tag) : undefined;
|
|
3841
|
+
const lang = tagLang ??
|
|
3842
|
+
(workbookLocale ? cjkLangOfTag(workbookLocale) : undefined) ??
|
|
3843
|
+
"ja";
|
|
3844
|
+
const gannen = !!tag && tag.toLowerCase().includes("-x-gannen");
|
|
3845
|
+
const date = serialToDate(value);
|
|
3846
|
+
const sections = splitFormatSections(code);
|
|
3847
|
+
const rewritten = [];
|
|
3848
|
+
const levels = [];
|
|
3849
|
+
const dated = [];
|
|
3850
|
+
let changed = false;
|
|
3851
|
+
for (const section of sections) {
|
|
3852
|
+
const level = dbnumLevel(section);
|
|
3853
|
+
const result = rewriteSection(section, {
|
|
3854
|
+
dbnum: level === undefined ? undefined : { level, lang },
|
|
3855
|
+
weekdayLang: lang,
|
|
3856
|
+
eraYears: tagLang === "ja" || hasEraNameToken(section),
|
|
3857
|
+
gannen,
|
|
3858
|
+
date,
|
|
3859
|
+
});
|
|
3860
|
+
changed ||= result.changed || level !== undefined;
|
|
3861
|
+
rewritten.push(result.text);
|
|
3862
|
+
levels.push(level);
|
|
3863
|
+
dated.push(result.dateToken);
|
|
3864
|
+
}
|
|
3865
|
+
if (!changed)
|
|
3866
|
+
return undefined;
|
|
3867
|
+
const anyCondition = sections.some((s) => analyzeFormatSection(s).hasCondition);
|
|
3868
|
+
const index = anyCondition
|
|
3869
|
+
? 0
|
|
3870
|
+
: Math.min(pickNumberSection(sections.length, value).index, sections.length - 1);
|
|
3871
|
+
const level = levels[index];
|
|
3872
|
+
const dbnum = level !== undefined && (level <= 3 || (level === 4 && lang === "ko"))
|
|
3873
|
+
? { level, lang }
|
|
3874
|
+
: undefined;
|
|
3875
|
+
let mode;
|
|
3876
|
+
if (dated[index]) {
|
|
3877
|
+
mode = "date";
|
|
3878
|
+
}
|
|
3879
|
+
else {
|
|
3880
|
+
switch (analyzeFormatSection(stripDbNum(sections[index])).kind) {
|
|
3881
|
+
case "general":
|
|
3882
|
+
mode = "general";
|
|
3883
|
+
break;
|
|
3884
|
+
case "date":
|
|
3885
|
+
mode = "date";
|
|
3886
|
+
break;
|
|
3887
|
+
case "number":
|
|
3888
|
+
case "other":
|
|
3889
|
+
mode = "digits";
|
|
3890
|
+
break;
|
|
3891
|
+
default:
|
|
3892
|
+
mode = "unchanged";
|
|
3893
|
+
}
|
|
3894
|
+
}
|
|
3895
|
+
return {
|
|
3896
|
+
code: rewritten.join(";"),
|
|
3897
|
+
finish: (out) => dbnum && mode !== "unchanged" ? convertDigits(out, dbnum, mode) : out,
|
|
3898
|
+
};
|
|
3899
|
+
};
|
|
3900
|
+
const runLength = (chars, from, letter) => {
|
|
3901
|
+
let n = 0;
|
|
3902
|
+
while (from + n < chars.length && chars[from + n].toLowerCase() === letter)
|
|
3903
|
+
n += 1;
|
|
3904
|
+
return n;
|
|
3905
|
+
};
|
|
3906
|
+
const startsWithCi = (chars, from, word) => chars
|
|
3907
|
+
.slice(from, from + word.length)
|
|
3908
|
+
.join("")
|
|
3909
|
+
.toLowerCase() === word;
|
|
3910
|
+
const quote = (text) => `"${text}"`;
|
|
3911
|
+
const rewriteSection = (section, ctx) => {
|
|
3912
|
+
const chars = Array.from(section);
|
|
3913
|
+
let out = "";
|
|
3914
|
+
let changed = false;
|
|
3915
|
+
let dateToken = false;
|
|
3916
|
+
let i = 0;
|
|
3917
|
+
while (i < chars.length) {
|
|
3918
|
+
const c = chars[i];
|
|
3919
|
+
const lower = c.toLowerCase();
|
|
3920
|
+
if (c === '"') {
|
|
3921
|
+
const close = chars.indexOf('"', i + 1);
|
|
3922
|
+
const end = close === -1 ? chars.length : close + 1;
|
|
3923
|
+
out += chars.slice(i, end).join("");
|
|
3924
|
+
i = end;
|
|
3925
|
+
}
|
|
3926
|
+
else if (c === "\\" || c === "_" || c === "*") {
|
|
3927
|
+
out += chars.slice(i, i + 2).join("");
|
|
3928
|
+
i += 2;
|
|
3929
|
+
}
|
|
3930
|
+
else if (c === "[") {
|
|
3931
|
+
const close = chars.indexOf("]", i);
|
|
3932
|
+
const end = close === -1 ? chars.length : close + 1;
|
|
3933
|
+
const token = chars.slice(i, end).join("");
|
|
3934
|
+
if (DBNUM_TOKEN.test(token))
|
|
3935
|
+
changed = true;
|
|
3936
|
+
else
|
|
3937
|
+
out += token;
|
|
3938
|
+
i = end;
|
|
3939
|
+
}
|
|
3940
|
+
else if (lower === "g" && startsWithCi(chars, i, "general")) {
|
|
3941
|
+
out += chars.slice(i, i + 7).join("");
|
|
3942
|
+
i += 7;
|
|
3943
|
+
}
|
|
3944
|
+
else if (lower === "g") {
|
|
3945
|
+
const run = runLength(chars, i, "g");
|
|
3946
|
+
if (ctx.date) {
|
|
3947
|
+
const era = eraOf(ctx.date);
|
|
3948
|
+
out += quote(run === 1 ? era.letter : run === 2 ? era.short : era.name);
|
|
3949
|
+
}
|
|
3950
|
+
changed = true;
|
|
3951
|
+
dateToken = true;
|
|
3952
|
+
i += run;
|
|
3953
|
+
}
|
|
3954
|
+
else if (lower === "e" && chars[i + 1] !== "+" && chars[i + 1] !== "-") {
|
|
3955
|
+
const run = runLength(chars, i, "e");
|
|
3956
|
+
if (ctx.date && ctx.eraYears) {
|
|
3957
|
+
const eraYear = ctx.date.year - eraOf(ctx.date).start[0] + 1;
|
|
3958
|
+
const text = eraYear === 1 && ctx.gannen
|
|
3959
|
+
? "元"
|
|
3960
|
+
: run >= 2
|
|
3961
|
+
? String(eraYear).padStart(2, "0")
|
|
3962
|
+
: String(eraYear);
|
|
3963
|
+
out += quote(text);
|
|
3964
|
+
changed = true;
|
|
3965
|
+
dateToken = true;
|
|
3966
|
+
}
|
|
3967
|
+
else if (ctx.date && ctx.dbnum) {
|
|
3968
|
+
out += quote(perDigit(String(ctx.date.year), ctx.dbnum));
|
|
3969
|
+
changed = true;
|
|
3970
|
+
dateToken = true;
|
|
3971
|
+
}
|
|
3972
|
+
else {
|
|
3973
|
+
out += chars.slice(i, i + run).join("");
|
|
3974
|
+
}
|
|
3975
|
+
i += run;
|
|
3976
|
+
}
|
|
3977
|
+
else if (lower === "a" && startsWithCi(chars, i, "am/pm")) {
|
|
3978
|
+
out += chars.slice(i, i + 5).join("");
|
|
3979
|
+
i += 5;
|
|
3980
|
+
}
|
|
3981
|
+
else if (lower === "a" && startsWithCi(chars, i, "a/p")) {
|
|
3982
|
+
out += chars.slice(i, i + 3).join("");
|
|
3983
|
+
i += 3;
|
|
3984
|
+
}
|
|
3985
|
+
else if (lower === "a" && runLength(chars, i, "a") >= 3) {
|
|
3986
|
+
const run = runLength(chars, i, "a");
|
|
3987
|
+
if (ctx.date)
|
|
3988
|
+
out += quote(weekdayName(ctx.weekdayLang, ctx.date.weekday, run >= 4));
|
|
3989
|
+
changed = true;
|
|
3990
|
+
dateToken = true;
|
|
3991
|
+
i += run;
|
|
3992
|
+
}
|
|
3993
|
+
else if (lower === "y" && ctx.dbnum && ctx.date) {
|
|
3994
|
+
const run = runLength(chars, i, "y");
|
|
3995
|
+
const digits = run <= 2
|
|
3996
|
+
? String(ctx.date.year % 100).padStart(2, "0")
|
|
3997
|
+
: String(ctx.date.year);
|
|
3998
|
+
out += quote(perDigit(digits, ctx.dbnum));
|
|
3999
|
+
changed = true;
|
|
4000
|
+
dateToken = true;
|
|
4001
|
+
i += run;
|
|
4002
|
+
}
|
|
4003
|
+
else {
|
|
4004
|
+
out += c;
|
|
4005
|
+
i += 1;
|
|
4006
|
+
}
|
|
4007
|
+
}
|
|
4008
|
+
return { text: out, changed, dateToken };
|
|
4009
|
+
};
|
|
4010
|
+
/** `[...]` tokens outside quoted literals and escapes. */
|
|
4011
|
+
const bracketTokens = (section) => {
|
|
4012
|
+
const tokens = [];
|
|
4013
|
+
let inQuotes = false;
|
|
4014
|
+
for (let i = 0; i < section.length; i += 1) {
|
|
4015
|
+
const c = section[i];
|
|
4016
|
+
if (c === '"')
|
|
4017
|
+
inQuotes = !inQuotes;
|
|
4018
|
+
else if (!inQuotes && (c === "\\" || c === "_" || c === "*"))
|
|
4019
|
+
i += 1;
|
|
4020
|
+
else if (!inQuotes && c === "[") {
|
|
4021
|
+
const end = section.indexOf("]", i);
|
|
4022
|
+
if (end !== -1) {
|
|
4023
|
+
tokens.push(section.slice(i, end + 1));
|
|
4024
|
+
i = end;
|
|
4025
|
+
}
|
|
4026
|
+
}
|
|
4027
|
+
}
|
|
4028
|
+
return tokens;
|
|
4029
|
+
};
|
|
4030
|
+
const dbnumLevel = (section) => {
|
|
4031
|
+
for (const token of bracketTokens(section)) {
|
|
4032
|
+
const m = DBNUM_TOKEN.exec(token);
|
|
4033
|
+
if (m)
|
|
4034
|
+
return Number(m[1]);
|
|
4035
|
+
}
|
|
4036
|
+
return undefined;
|
|
4037
|
+
};
|
|
4038
|
+
const stripDbNum = (section) => bracketTokens(section)
|
|
4039
|
+
.filter((t) => DBNUM_TOKEN.test(t))
|
|
4040
|
+
.reduce((s, t) => s.replace(t, ""), section);
|
|
4041
|
+
/** Whether a section names an era (`g`) outside quotes, brackets and `General`. */
|
|
4042
|
+
const hasEraNameToken = (section) => {
|
|
4043
|
+
let inQuotes = false;
|
|
4044
|
+
let inBrackets = false;
|
|
4045
|
+
for (let i = 0; i < section.length; i += 1) {
|
|
4046
|
+
const c = section[i];
|
|
4047
|
+
if (inQuotes)
|
|
4048
|
+
inQuotes = c !== '"';
|
|
4049
|
+
else if (inBrackets)
|
|
4050
|
+
inBrackets = c !== "]";
|
|
4051
|
+
else if (c === '"')
|
|
4052
|
+
inQuotes = true;
|
|
4053
|
+
else if (c === "[")
|
|
4054
|
+
inBrackets = true;
|
|
4055
|
+
else if (c === "\\" || c === "_" || c === "*")
|
|
4056
|
+
i += 1;
|
|
4057
|
+
else if (c.toLowerCase() === "g") {
|
|
4058
|
+
if (section.slice(i, i + 7).toLowerCase() === "general")
|
|
4059
|
+
i += 6;
|
|
4060
|
+
else
|
|
4061
|
+
return true;
|
|
4062
|
+
}
|
|
4063
|
+
}
|
|
4064
|
+
return false;
|
|
4065
|
+
};
|
|
4066
|
+
/** The locale spec of the code's first `[$…-spec]` token (`411`, `ja-JP`, `ja-JP-x-gannen`). */
|
|
4067
|
+
const localeTag = (code) => {
|
|
4068
|
+
const start = code.indexOf("[$");
|
|
4069
|
+
if (start === -1)
|
|
4070
|
+
return undefined;
|
|
4071
|
+
const end = code.indexOf("]", start);
|
|
4072
|
+
if (end === -1)
|
|
4073
|
+
return undefined;
|
|
4074
|
+
const inner = code.slice(start + 2, end);
|
|
4075
|
+
const dash = inner.indexOf("-");
|
|
4076
|
+
if (dash === -1)
|
|
4077
|
+
return undefined;
|
|
4078
|
+
const spec = inner.slice(dash + 1);
|
|
4079
|
+
return spec || undefined;
|
|
4080
|
+
};
|
|
4081
|
+
/** Language of an LCID (hex, low 16 bits) or a BCP-47 tag, for the CJK locales. */
|
|
4082
|
+
const cjkLangOfTag = (input) => {
|
|
4083
|
+
const spec = input.split(",")[0].trim();
|
|
4084
|
+
if (/^[0-9a-f]+$/i.test(spec)) {
|
|
4085
|
+
switch (parseInt(spec, 16) & 0xffff) {
|
|
4086
|
+
case 0x0411:
|
|
4087
|
+
return "ja";
|
|
4088
|
+
case 0x0804:
|
|
4089
|
+
case 0x1004:
|
|
4090
|
+
return "zh-Hans";
|
|
4091
|
+
case 0x0404:
|
|
4092
|
+
case 0x0c04:
|
|
4093
|
+
case 0x1404:
|
|
4094
|
+
return "zh-Hant";
|
|
4095
|
+
case 0x0412:
|
|
4096
|
+
return "ko";
|
|
4097
|
+
default:
|
|
4098
|
+
return undefined;
|
|
4099
|
+
}
|
|
4100
|
+
}
|
|
4101
|
+
const [primary, ...rest] = spec.toLowerCase().split(/[-_]/);
|
|
4102
|
+
if (primary === "ja")
|
|
4103
|
+
return "ja";
|
|
4104
|
+
if (primary === "ko")
|
|
4105
|
+
return "ko";
|
|
4106
|
+
if (primary === "zh") {
|
|
4107
|
+
return rest.some((p) => p === "hant" || p === "tw" || p === "hk" || p === "mo")
|
|
4108
|
+
? "zh-Hant"
|
|
4109
|
+
: "zh-Hans";
|
|
4110
|
+
}
|
|
4111
|
+
return undefined;
|
|
4112
|
+
};
|
|
4113
|
+
// ---- dates ------------------------------------------------------------------------------------
|
|
4114
|
+
/**
|
|
4115
|
+
* Excel 1900-system serial → calendar date, keeping Excel's fictitious 1900-02-29 (serial 60)
|
|
4116
|
+
* and its weekday numbering (serial 1 is a Sunday). The time of day rounds to the nearest second.
|
|
4117
|
+
*/
|
|
4118
|
+
const serialToDate = (value) => {
|
|
4119
|
+
if (!Number.isFinite(value) || value < 0 || value >= 2958466)
|
|
4120
|
+
return undefined;
|
|
4121
|
+
const days = Math.floor(Math.round(value * 86400) / 86400);
|
|
4122
|
+
const weekday = (days + 6) % 7;
|
|
4123
|
+
if (days === 60)
|
|
4124
|
+
return { year: 1900, month: 2, day: 29, weekday };
|
|
4125
|
+
const offset = days < 60 ? days : days - 1;
|
|
4126
|
+
const d = new Date(Date.UTC(1899, 11, 31) + offset * 86400000);
|
|
4127
|
+
return {
|
|
4128
|
+
year: d.getUTCFullYear(),
|
|
4129
|
+
month: d.getUTCMonth() + 1,
|
|
4130
|
+
day: d.getUTCDate(),
|
|
4131
|
+
weekday,
|
|
4132
|
+
};
|
|
4133
|
+
};
|
|
4134
|
+
/** Japanese eras with the start dates Windows' Japanese calendar (and so Excel) uses. */
|
|
4135
|
+
const ERAS = [
|
|
4136
|
+
{ start: [1868, 1, 1], letter: "M", short: "明", name: "明治" },
|
|
4137
|
+
{ start: [1912, 7, 30], letter: "T", short: "大", name: "大正" },
|
|
4138
|
+
{ start: [1926, 12, 25], letter: "S", short: "昭", name: "昭和" },
|
|
4139
|
+
{ start: [1989, 1, 8], letter: "H", short: "平", name: "平成" },
|
|
4140
|
+
{ start: [2019, 5, 1], letter: "R", short: "令", name: "令和" },
|
|
4141
|
+
];
|
|
4142
|
+
const eraOf = (date) => {
|
|
4143
|
+
const key = date.year * 10000 + date.month * 100 + date.day;
|
|
4144
|
+
for (let i = ERAS.length - 1; i >= 0; i -= 1) {
|
|
4145
|
+
const [y, m, d] = ERAS[i].start;
|
|
4146
|
+
if (key >= y * 10000 + m * 100 + d)
|
|
4147
|
+
return ERAS[i];
|
|
4148
|
+
}
|
|
4149
|
+
return ERAS[0];
|
|
4150
|
+
};
|
|
4151
|
+
const weekdayName = (lang, weekday, long) => {
|
|
4152
|
+
const w = weekday % 7;
|
|
4153
|
+
switch (lang) {
|
|
4154
|
+
case "ja": {
|
|
4155
|
+
const short = "日月火水木金土"[w];
|
|
4156
|
+
return long ? `${short}曜日` : short;
|
|
4157
|
+
}
|
|
4158
|
+
case "ko": {
|
|
4159
|
+
const short = "일월화수목금토"[w];
|
|
4160
|
+
return long ? `${short}요일` : short;
|
|
4161
|
+
}
|
|
4162
|
+
default: {
|
|
4163
|
+
const short = "日一二三四五六"[w];
|
|
4164
|
+
return long ? `星期${short}` : short;
|
|
4165
|
+
}
|
|
4166
|
+
}
|
|
4167
|
+
};
|
|
4168
|
+
const KANJI = Array.from("〇一二三四五六七八九");
|
|
4169
|
+
const FULL_WIDTH = Array.from("0123456789");
|
|
4170
|
+
const BIG_HANS = ["万", "亿", "兆"];
|
|
4171
|
+
const BIG_TRAD = ["萬", "億", "兆"];
|
|
4172
|
+
const BIG_JA = ["万", "億", "兆"];
|
|
4173
|
+
const numerals = ({ level, lang }) => {
|
|
4174
|
+
const zh = lang === "zh-Hans" || lang === "zh-Hant";
|
|
4175
|
+
const level1Big = lang === "ja" ? BIG_JA : lang === "zh-Hans" ? BIG_HANS : BIG_TRAD;
|
|
4176
|
+
if (level === 2) {
|
|
4177
|
+
switch (lang) {
|
|
4178
|
+
case "ja":
|
|
4179
|
+
return {
|
|
4180
|
+
digits: Array.from("〇壱弐参四伍六七八九"),
|
|
4181
|
+
small: ["拾", "百", "阡"],
|
|
4182
|
+
big: BIG_TRAD,
|
|
4183
|
+
omitOne: false,
|
|
4184
|
+
fillZero: false,
|
|
4185
|
+
};
|
|
4186
|
+
case "zh-Hans":
|
|
4187
|
+
return {
|
|
4188
|
+
digits: Array.from("零壹贰叁肆伍陆柒捌玖"),
|
|
4189
|
+
small: ["拾", "佰", "仟"],
|
|
4190
|
+
big: BIG_HANS,
|
|
4191
|
+
omitOne: false,
|
|
4192
|
+
fillZero: true,
|
|
4193
|
+
};
|
|
4194
|
+
case "zh-Hant":
|
|
4195
|
+
return {
|
|
4196
|
+
digits: Array.from("零壹貳參肆伍陸柒捌玖"),
|
|
4197
|
+
small: ["拾", "佰", "仟"],
|
|
4198
|
+
big: BIG_TRAD,
|
|
4199
|
+
omitOne: false,
|
|
4200
|
+
fillZero: true,
|
|
4201
|
+
};
|
|
4202
|
+
case "ko":
|
|
4203
|
+
return {
|
|
4204
|
+
digits: Array.from("零壹貳參四伍六七八九"),
|
|
4205
|
+
small: ["拾", "百", "阡"],
|
|
4206
|
+
big: BIG_TRAD,
|
|
4207
|
+
omitOne: false,
|
|
4208
|
+
fillZero: false,
|
|
4209
|
+
};
|
|
4210
|
+
}
|
|
4211
|
+
}
|
|
4212
|
+
if (level === 3) {
|
|
4213
|
+
return {
|
|
4214
|
+
digits: FULL_WIDTH,
|
|
4215
|
+
small: ["十", "百", "千"],
|
|
4216
|
+
big: level1Big,
|
|
4217
|
+
omitOne: false,
|
|
4218
|
+
fillZero: zh,
|
|
4219
|
+
};
|
|
4220
|
+
}
|
|
4221
|
+
if (level === 4 && lang === "ko") {
|
|
4222
|
+
return {
|
|
4223
|
+
digits: Array.from("영일이삼사오육칠팔구"),
|
|
4224
|
+
small: ["십", "백", "천"],
|
|
4225
|
+
big: ["만", "억", "조"],
|
|
4226
|
+
omitOne: true,
|
|
4227
|
+
fillZero: false,
|
|
4228
|
+
};
|
|
4229
|
+
}
|
|
4230
|
+
return {
|
|
4231
|
+
digits: KANJI,
|
|
4232
|
+
small: ["十", "百", "千"],
|
|
4233
|
+
big: level1Big,
|
|
4234
|
+
omitOne: !zh,
|
|
4235
|
+
fillZero: zh,
|
|
4236
|
+
};
|
|
4237
|
+
};
|
|
4238
|
+
const perDigit = (digits, dbnum) => {
|
|
4239
|
+
const table = numerals(dbnum).digits;
|
|
4240
|
+
return Array.from(digits)
|
|
4241
|
+
.map((c) => (c >= "0" && c <= "9" ? table[Number(c)] : c))
|
|
4242
|
+
.join("");
|
|
4243
|
+
};
|
|
4244
|
+
/** `digits` read as a number with units; past 兆 (≥ 10^16) digit by digit. */
|
|
4245
|
+
const withUnits = (digits, dbnum) => {
|
|
4246
|
+
const n = numerals(dbnum);
|
|
4247
|
+
const trimmed = digits.replace(/^0+/, "");
|
|
4248
|
+
if (!trimmed)
|
|
4249
|
+
return n.digits[0];
|
|
4250
|
+
if (trimmed.length > 16)
|
|
4251
|
+
return perDigit(digits, dbnum);
|
|
4252
|
+
const values = Array.from(trimmed, Number);
|
|
4253
|
+
const groups = Math.ceil(values.length / 4);
|
|
4254
|
+
let out = "";
|
|
4255
|
+
let pendingZero = false;
|
|
4256
|
+
for (let g = 0; g < groups; g += 1) {
|
|
4257
|
+
const groupIndex = groups - 1 - g;
|
|
4258
|
+
const end = values.length - groupIndex * 4;
|
|
4259
|
+
const group = values.slice(Math.max(0, end - 4), end);
|
|
4260
|
+
let wrote = false;
|
|
4261
|
+
group.forEach((d, k) => {
|
|
4262
|
+
const pos = group.length - 1 - k;
|
|
4263
|
+
if (d === 0) {
|
|
4264
|
+
pendingZero ||= out.length > 0 || wrote;
|
|
4265
|
+
return;
|
|
4266
|
+
}
|
|
4267
|
+
if (pendingZero && n.fillZero)
|
|
4268
|
+
out += "零";
|
|
4269
|
+
pendingZero = false;
|
|
4270
|
+
if (!(d === 1 && pos > 0 && n.omitOne))
|
|
4271
|
+
out += n.digits[d];
|
|
4272
|
+
if (pos > 0)
|
|
4273
|
+
out += n.small[pos - 1];
|
|
4274
|
+
wrote = true;
|
|
4275
|
+
});
|
|
4276
|
+
if (wrote && groupIndex > 0)
|
|
4277
|
+
out += n.big[groupIndex - 1];
|
|
4278
|
+
}
|
|
4279
|
+
return out;
|
|
4280
|
+
};
|
|
4281
|
+
const isAsciiDigit = (c) => !!c && c >= "0" && c <= "9";
|
|
4282
|
+
const convertDigits = (text, dbnum, mode) => {
|
|
4283
|
+
const chars = Array.from(text);
|
|
4284
|
+
let out = "";
|
|
4285
|
+
let i = 0;
|
|
4286
|
+
while (i < chars.length) {
|
|
4287
|
+
if (!isAsciiDigit(chars[i])) {
|
|
4288
|
+
out += chars[i];
|
|
4289
|
+
i += 1;
|
|
4290
|
+
continue;
|
|
4291
|
+
}
|
|
4292
|
+
let end = i;
|
|
4293
|
+
while (end < chars.length && isAsciiDigit(chars[end]))
|
|
4294
|
+
end += 1;
|
|
4295
|
+
const run = chars.slice(i, end).join("");
|
|
4296
|
+
const fraction = i >= 2 &&
|
|
4297
|
+
(chars[i - 1] === "." || chars[i - 1] === ",") &&
|
|
4298
|
+
isAsciiDigit(chars[i - 2]);
|
|
4299
|
+
const units = mode === "date"
|
|
4300
|
+
? dbnum.level !== 3
|
|
4301
|
+
: mode === "general"
|
|
4302
|
+
? !fraction
|
|
4303
|
+
: false;
|
|
4304
|
+
out += units ? withUnits(run, dbnum) : perDigit(run, dbnum);
|
|
4305
|
+
i = end;
|
|
4306
|
+
}
|
|
4307
|
+
return out;
|
|
4308
|
+
};
|
|
4309
|
+
|
|
3804
4310
|
// Excel indexed colors mapping used for legacy color references
|
|
3805
4311
|
const IndexedColors = Object.freeze([
|
|
3806
4312
|
// 0-7
|
|
@@ -3877,35 +4383,44 @@ const IndexedColors = Object.freeze([
|
|
|
3877
4383
|
"#333333",
|
|
3878
4384
|
]);
|
|
3879
4385
|
|
|
3880
|
-
const isSingleSectionElapsedTimePattern = (pattern) => !pattern.includes(";") &&
|
|
3881
|
-
/\[(?:h+|m+|s+)\]/i.test(pattern.replace(/\[\$[^\]]+\]/g, ""));
|
|
3882
4386
|
const intlMonthNames = (locale, options) => {
|
|
3883
4387
|
const formatter = new Intl.DateTimeFormat(locale, {
|
|
3884
4388
|
...options,
|
|
3885
4389
|
timeZone: "UTC",
|
|
3886
4390
|
});
|
|
3887
|
-
|
|
3888
|
-
.formatToParts(new Date(Date.UTC(2020, month, 1)))
|
|
3889
|
-
.
|
|
4391
|
+
const names = Array.from({ length: 12 }, (_, month) => {
|
|
4392
|
+
const parts = formatter.formatToParts(new Date(Date.UTC(2020, month, 1)));
|
|
4393
|
+
const index = parts.findIndex((part) => part.type === "month");
|
|
4394
|
+
const name = parts[index]?.value ?? "";
|
|
4395
|
+
// A numeric month comes split from its counter ("1" + "月"); the CLDR
|
|
4396
|
+
// name on its own (what the Rust engine renders) is "1月".
|
|
4397
|
+
const next = parts[index + 1];
|
|
4398
|
+
return /^\d+$/.test(name) && next?.type === "literal" && !/\d/.test(next.value)
|
|
4399
|
+
? name + next.value.trim()
|
|
4400
|
+
: name;
|
|
4401
|
+
});
|
|
4402
|
+
// Beside a day, zh/ja write the month as a number ("3月15日") even where
|
|
4403
|
+
// CLDR's `MMMM` on its own is a word (zh "三月"): take the standalone name.
|
|
4404
|
+
if (options.day && names.every((name) => /^\d/.test(name))) {
|
|
4405
|
+
return intlMonthNames(locale, { month: options.month });
|
|
4406
|
+
}
|
|
4407
|
+
return names;
|
|
3890
4408
|
};
|
|
3891
4409
|
const intlRegisteredLocales = new Set();
|
|
3892
4410
|
/**
|
|
3893
|
-
*
|
|
3894
|
-
* (
|
|
3895
|
-
* separators
|
|
3896
|
-
*
|
|
3897
|
-
*
|
|
3898
|
-
*
|
|
3899
|
-
*
|
|
3900
|
-
* designators. Tags Intl itself does not know keep numfmt's fallback.
|
|
4411
|
+
* Every locale renders from a numfmt locale built from Intl (CLDR) the way the
|
|
4412
|
+
* Rust engine (the Excel reference, `rnc_cellmodel::locale_data`) builds its
|
|
4413
|
+
* own: separators from `Intl.NumberFormat`, the in-date month and weekday
|
|
4414
|
+
* names, and English `AM`/`PM` and `TRUE`/`FALSE` (numfmt's defaults), not
|
|
4415
|
+
* numfmt's shipped tables (de `WAHR`, ja `午前`, en-GB `Sep`). A month shown
|
|
4416
|
+
* without a day takes the standalone names (`getStandaloneMonthLocale`). Tags
|
|
4417
|
+
* Intl does not know keep numfmt's fallback.
|
|
3901
4418
|
*/
|
|
3902
4419
|
const ensureNumfmtLocale = (locale) => {
|
|
3903
4420
|
if (intlRegisteredLocales.has(locale))
|
|
3904
4421
|
return;
|
|
3905
4422
|
intlRegisteredLocales.add(locale);
|
|
3906
4423
|
try {
|
|
3907
|
-
if (getLocale(locale))
|
|
3908
|
-
return;
|
|
3909
4424
|
const canonical = Intl.DateTimeFormat.supportedLocalesOf([locale])[0];
|
|
3910
4425
|
if (!canonical)
|
|
3911
4426
|
return;
|
|
@@ -3924,20 +4439,11 @@ const ensureNumfmtLocale = (locale) => {
|
|
|
3924
4439
|
.formatToParts(new Date(Date.UTC(2024, 0, 7 + i)))
|
|
3925
4440
|
.find((p) => p.type === "weekday")?.value ?? "");
|
|
3926
4441
|
};
|
|
3927
|
-
const dayPeriod = (hour) => new Intl.DateTimeFormat(locale, {
|
|
3928
|
-
hour: "numeric",
|
|
3929
|
-
hour12: true,
|
|
3930
|
-
timeZone: "UTC",
|
|
3931
|
-
})
|
|
3932
|
-
.formatToParts(new Date(Date.UTC(2024, 0, 7, hour)))
|
|
3933
|
-
.find((p) => p.type === "dayPeriod")?.value;
|
|
3934
4442
|
const dateParts = new Intl.DateTimeFormat(locale, {
|
|
3935
4443
|
timeZone: "UTC",
|
|
3936
4444
|
}).formatToParts(new Date(Date.UTC(2024, 0, 7)));
|
|
3937
4445
|
const monthIndex = dateParts.findIndex((p) => p.type === "month");
|
|
3938
4446
|
const dayIndex = dateParts.findIndex((p) => p.type === "day");
|
|
3939
|
-
const am = dayPeriod(9);
|
|
3940
|
-
const pm = dayPeriod(21);
|
|
3941
4447
|
addLocale({
|
|
3942
4448
|
group: part("group") ?? "\u00a0",
|
|
3943
4449
|
decimal: part("decimal") ?? ".",
|
|
@@ -3945,7 +4451,6 @@ const ensureNumfmtLocale = (locale) => {
|
|
|
3945
4451
|
mmm: intlMonthNames(locale, { day: "numeric", month: "short" }),
|
|
3946
4452
|
dddd: weekdayNames("long"),
|
|
3947
4453
|
ddd: weekdayNames("short"),
|
|
3948
|
-
...(am && pm && am !== pm ? { ampm: [am, pm] } : {}),
|
|
3949
4454
|
preferMDY: monthIndex >= 0 && dayIndex >= 0 && monthIndex < dayIndex,
|
|
3950
4455
|
}, locale);
|
|
3951
4456
|
}
|
|
@@ -3953,6 +4458,31 @@ const ensureNumfmtLocale = (locale) => {
|
|
|
3953
4458
|
// Malformed tag: numfmt keeps its own fallback.
|
|
3954
4459
|
}
|
|
3955
4460
|
};
|
|
4461
|
+
const scientificLocales = new Map();
|
|
4462
|
+
/**
|
|
4463
|
+
* The Rust engine (ssfmt) renders a scientific mantissa with `.` in every
|
|
4464
|
+
* locale (`1.00E+03` in de-DE), so an exponent section renders under a
|
|
4465
|
+
* companion locale whose decimal separator is `.`.
|
|
4466
|
+
*/
|
|
4467
|
+
const getScientificLocale = (locale) => {
|
|
4468
|
+
const cached = scientificLocales.get(locale);
|
|
4469
|
+
if (cached !== undefined)
|
|
4470
|
+
return cached;
|
|
4471
|
+
let overlay = locale;
|
|
4472
|
+
try {
|
|
4473
|
+
const base = getLocale(locale);
|
|
4474
|
+
if (base && base.decimal !== ".") {
|
|
4475
|
+
overlay = `sci_${locale.replace(/[^a-z\d]/gi, "")}`;
|
|
4476
|
+
addLocale({ ...base, decimal: "." }, overlay);
|
|
4477
|
+
}
|
|
4478
|
+
}
|
|
4479
|
+
catch {
|
|
4480
|
+
overlay = locale;
|
|
4481
|
+
}
|
|
4482
|
+
scientificLocales.set(locale, overlay);
|
|
4483
|
+
return overlay;
|
|
4484
|
+
};
|
|
4485
|
+
const SCIENTIFIC_SECTION = /^(?:"[^"]*"|\[[^\]]*\]|\\.|[^"\[\\eE])*[eE][+-]/;
|
|
3956
4486
|
const localeForPattern = (pattern, locale) => {
|
|
3957
4487
|
return locale;
|
|
3958
4488
|
};
|
|
@@ -4203,6 +4733,17 @@ const withWorkbookSeparatorsCached = (code, locale) => {
|
|
|
4203
4733
|
return rewritten;
|
|
4204
4734
|
};
|
|
4205
4735
|
const ssfFormat = (pattern, value, locale) => {
|
|
4736
|
+
// East Asian tokens numfmt does not render (`[DBNumN]`, Japanese era `g`/`e`,
|
|
4737
|
+
// `aaa` weekdays): rewrite the code to plain literals, then convert the
|
|
4738
|
+
// rendered digits to the `[DBNumN]` numeral system (see cjk-number-format).
|
|
4739
|
+
if (typeof value === "number") {
|
|
4740
|
+
const cjk = prepareCjkNumberFormat(pattern, value, locale);
|
|
4741
|
+
if (cjk)
|
|
4742
|
+
return cjk.finish(ssfFormatBase(cjk.code, value, locale));
|
|
4743
|
+
}
|
|
4744
|
+
return ssfFormatBase(pattern, value, locale);
|
|
4745
|
+
};
|
|
4746
|
+
function ssfFormatBase(pattern, value, locale, layout) {
|
|
4206
4747
|
try {
|
|
4207
4748
|
if (locale)
|
|
4208
4749
|
;
|
|
@@ -4211,12 +4752,25 @@ const ssfFormat = (pattern, value, locale) => {
|
|
|
4211
4752
|
shortAmPm = withShortAmPmMarker(pattern);
|
|
4212
4753
|
shortAmPmPatternCache.set(pattern, shortAmPm);
|
|
4213
4754
|
}
|
|
4214
|
-
const
|
|
4755
|
+
const baseCode = withWorkbookSeparatorsCached(shortAmPm ?? pattern, locale);
|
|
4756
|
+
const code = layout ? layout.transform(baseCode) : baseCode;
|
|
4215
4757
|
let patternLocale = localeForPattern(pattern, locale);
|
|
4758
|
+
if (patternLocale && SCIENTIFIC_SECTION.test(pattern)) {
|
|
4759
|
+
patternLocale = getScientificLocale(patternLocale);
|
|
4760
|
+
}
|
|
4216
4761
|
if (shortAmPm !== undefined && patternLocale) {
|
|
4217
4762
|
patternLocale = getShortAmPmLocale(patternLocale);
|
|
4218
4763
|
}
|
|
4219
|
-
|
|
4764
|
+
// numfmt types `fillChar` / `skipChar` as booleans; at runtime they are
|
|
4765
|
+
// the marker strings it emits ahead of the fill / skip character.
|
|
4766
|
+
const options = layout
|
|
4767
|
+
? {
|
|
4768
|
+
locale: patternLocale,
|
|
4769
|
+
nbsp: layout.nbsp,
|
|
4770
|
+
fillChar: layout.fillChar,
|
|
4771
|
+
skipChar: layout.skipChar,
|
|
4772
|
+
}
|
|
4773
|
+
: { locale: patternLocale };
|
|
4220
4774
|
if (typeof value === "number") {
|
|
4221
4775
|
// Excel decides rounding, `General`, huge magnitudes and conditional
|
|
4222
4776
|
// sections from the 15-significant-digit decimal, not the binary
|
|
@@ -4227,16 +4781,12 @@ const ssfFormat = (pattern, value, locale) => {
|
|
|
4227
4781
|
}
|
|
4228
4782
|
value = pre.value;
|
|
4229
4783
|
}
|
|
4230
|
-
|
|
4231
|
-
value < 0 &&
|
|
4232
|
-
isSingleSectionElapsedTimePattern(pattern);
|
|
4233
|
-
const formatted = format(code, isNegativeElapsedTime ? Math.abs(value) : value, options);
|
|
4234
|
-
return isNegativeElapsedTime ? `-${formatted}` : formatted;
|
|
4784
|
+
return format(code, value, options);
|
|
4235
4785
|
}
|
|
4236
4786
|
catch (err) {
|
|
4237
|
-
return String(value);
|
|
4787
|
+
return layout ? undefined : String(value);
|
|
4238
4788
|
}
|
|
4239
|
-
}
|
|
4789
|
+
}
|
|
4240
4790
|
for (let n = 1; n <= 56; n++) {
|
|
4241
4791
|
IndexedColors[n + 7];
|
|
4242
4792
|
}
|
|
@@ -4429,6 +4979,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
4429
4979
|
"FACTDOUBLE": "ZWEIFAKULTÄT",
|
|
4430
4980
|
"FALSE": "FALSCH",
|
|
4431
4981
|
"FDIST": "FVERT",
|
|
4982
|
+
"FIELDVALUE": "FELDWERT",
|
|
4432
4983
|
"FILTER": "FILTER",
|
|
4433
4984
|
"FILTERXML": "XMLFILTERN",
|
|
4434
4985
|
"FIND": "FINDEN",
|
|
@@ -4492,6 +5043,8 @@ const FORMULA_LOCALE_DATA = {
|
|
|
4492
5043
|
"IMLN": "IMLN",
|
|
4493
5044
|
"IMLOG10": "IMLOG10",
|
|
4494
5045
|
"IMLOG2": "IMLOG2",
|
|
5046
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
5047
|
+
"IMPORTTEXT": "IMPORTTEXT",
|
|
4495
5048
|
"IMPOWER": "IMAPOTENZ",
|
|
4496
5049
|
"IMPRODUCT": "IMPRODUKT",
|
|
4497
5050
|
"IMREAL": "IMREALTEIL",
|
|
@@ -4629,6 +5182,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
4629
5182
|
"PRODUCT": "PRODUKT",
|
|
4630
5183
|
"PROPER": "GROSS2",
|
|
4631
5184
|
"PV": "BW",
|
|
5185
|
+
"PY": "PY",
|
|
4632
5186
|
"QUARTILE": "QUARTILE",
|
|
4633
5187
|
"QUARTILE.EXC": "QUARTILE.EXKL",
|
|
4634
5188
|
"QUARTILE.INC": "QUARTILE.INKL",
|
|
@@ -4998,6 +5552,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
4998
5552
|
"FACTDOUBLE": "FACT.DOBLE",
|
|
4999
5553
|
"FALSE": "FALSO",
|
|
5000
5554
|
"FDIST": "DISTR.F",
|
|
5555
|
+
"FIELDVALUE": "VALORCAMPO",
|
|
5001
5556
|
"FILTER": "FILTRAR",
|
|
5002
5557
|
"FILTERXML": "XMLFILTRO",
|
|
5003
5558
|
"FIND": "ENCONTRAR",
|
|
@@ -5062,6 +5617,8 @@ const FORMULA_LOCALE_DATA = {
|
|
|
5062
5617
|
"IMLN": "IM.LN",
|
|
5063
5618
|
"IMLOG10": "IM.LOG10",
|
|
5064
5619
|
"IMLOG2": "IM.LOG2",
|
|
5620
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
5621
|
+
"IMPORTTEXT": "IMPORTTEXT",
|
|
5065
5622
|
"IMPOWER": "IM.POT",
|
|
5066
5623
|
"IMPRODUCT": "IM.PRODUCT",
|
|
5067
5624
|
"IMREAL": "IM.REAL",
|
|
@@ -5199,6 +5756,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
5199
5756
|
"PRODUCT": "PRODUCTO",
|
|
5200
5757
|
"PROPER": "NOMPROPIO",
|
|
5201
5758
|
"PV": "VA",
|
|
5759
|
+
"PY": "PY",
|
|
5202
5760
|
"QUARTILE": "CUARTIL",
|
|
5203
5761
|
"QUARTILE.EXC": "CUARTIL.EXC",
|
|
5204
5762
|
"QUARTILE.INC": "CUARTIL.INC",
|
|
@@ -5551,6 +6109,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
5551
6109
|
"FACTDOUBLE": "FACTDOUBLE",
|
|
5552
6110
|
"FALSE": "FAUX",
|
|
5553
6111
|
"FDIST": "LOI.F",
|
|
6112
|
+
"FIELDVALUE": "VALEURCHAMP",
|
|
5554
6113
|
"FILTER": "FILTRE",
|
|
5555
6114
|
"FILTERXML": "FILTRE.XML",
|
|
5556
6115
|
"FIND": "TROUVE",
|
|
@@ -5615,6 +6174,8 @@ const FORMULA_LOCALE_DATA = {
|
|
|
5615
6174
|
"IMLN": "COMPLEXE.LN",
|
|
5616
6175
|
"IMLOG10": "COMPLEXE.LOG10",
|
|
5617
6176
|
"IMLOG2": "COMPLEXE.LOG2",
|
|
6177
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
6178
|
+
"IMPORTTEXT": "IMPORTTEXT",
|
|
5618
6179
|
"IMPOWER": "COMPLEXE.PUISSANCE",
|
|
5619
6180
|
"IMPRODUCT": "COMPLEXE.PRODUIT",
|
|
5620
6181
|
"IMREAL": "COMPLEXE.REEL",
|
|
@@ -5750,6 +6311,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
5750
6311
|
"PRODUCT": "PRODUIT",
|
|
5751
6312
|
"PROPER": "NOMPROPRE",
|
|
5752
6313
|
"PV": "VA",
|
|
6314
|
+
"PY": "PY",
|
|
5753
6315
|
"QUARTILE": "QUARTILE",
|
|
5754
6316
|
"QUARTILE.EXC": "QUARTILE.EXCLURE",
|
|
5755
6317
|
"QUARTILE.INC": "QUARTILE.INCLURE",
|
|
@@ -6101,6 +6663,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
6101
6663
|
"FACTDOUBLE": "FATT.DOPPIO",
|
|
6102
6664
|
"FALSE": "FALSO",
|
|
6103
6665
|
"FDIST": "DISTRIB.F",
|
|
6666
|
+
"FIELDVALUE": "VALORECAMPO",
|
|
6104
6667
|
"FILTER": "FILTER",
|
|
6105
6668
|
"FILTERXML": "FILTRO.XML",
|
|
6106
6669
|
"FIND": "TROVA",
|
|
@@ -6165,6 +6728,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
6165
6728
|
"IMLN": "COMP.LN",
|
|
6166
6729
|
"IMLOG10": "COMP.LOG10",
|
|
6167
6730
|
"IMLOG2": "COMP.LOG2",
|
|
6731
|
+
"IMPORTTEXT": "IMPORTTEXT",
|
|
6168
6732
|
"IMPOWER": "COMP.POTENZA",
|
|
6169
6733
|
"IMPRODUCT": "COMP.PRODOTTO",
|
|
6170
6734
|
"IMREAL": "COMP.PARTE.REALE",
|
|
@@ -6302,6 +6866,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
6302
6866
|
"PRODUCT": "PRODOTTO",
|
|
6303
6867
|
"PROPER": "MAIUSC.INIZ",
|
|
6304
6868
|
"PV": "VA",
|
|
6869
|
+
"PY": "PY",
|
|
6305
6870
|
"QUARTILE": "QUARTILE",
|
|
6306
6871
|
"QUARTILE.EXC": "ESC.QUARTILE",
|
|
6307
6872
|
"QUARTILE.INC": "INC.QUARTILE",
|
|
@@ -6460,6 +7025,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
6460
7025
|
},
|
|
6461
7026
|
"uncertain": [
|
|
6462
7027
|
"FINDB",
|
|
7028
|
+
"IMPORTCSV",
|
|
6463
7029
|
"JIS",
|
|
6464
7030
|
"LEFTB",
|
|
6465
7031
|
"LENB",
|
|
@@ -6662,6 +7228,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
6662
7228
|
"FACTDOUBLE": "DUBBELE.FACULTEIT",
|
|
6663
7229
|
"FALSE": "ONWAAR",
|
|
6664
7230
|
"FDIST": "F.VERDELING",
|
|
7231
|
+
"FIELDVALUE": "VELDWAARDE",
|
|
6665
7232
|
"FILTER": "FILTER",
|
|
6666
7233
|
"FILTERXML": "XML.FILTEREN",
|
|
6667
7234
|
"FIND": "VIND.ALLES",
|
|
@@ -6726,6 +7293,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
6726
7293
|
"IMLN": "C.LN",
|
|
6727
7294
|
"IMLOG10": "C.LOG10",
|
|
6728
7295
|
"IMLOG2": "C.LOG2",
|
|
7296
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
6729
7297
|
"IMPOWER": "C.MACHT",
|
|
6730
7298
|
"IMPRODUCT": "C.PRODUCT",
|
|
6731
7299
|
"IMREAL": "C.REEEL.DEEL",
|
|
@@ -6863,6 +7431,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
6863
7431
|
"PRODUCT": "PRODUCT",
|
|
6864
7432
|
"PROPER": "BEGINLETTERS",
|
|
6865
7433
|
"PV": "HW",
|
|
7434
|
+
"PY": "PY",
|
|
6866
7435
|
"QUARTILE": "KWARTIEL",
|
|
6867
7436
|
"QUARTILE.EXC": "KWARTIEL.EXC",
|
|
6868
7437
|
"QUARTILE.INC": "KWARTIEL.INC",
|
|
@@ -7024,6 +7593,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
7024
7593
|
},
|
|
7025
7594
|
"uncertain": [
|
|
7026
7595
|
"FINDB",
|
|
7596
|
+
"IMPORTTEXT",
|
|
7027
7597
|
"JIS",
|
|
7028
7598
|
"LEFTB",
|
|
7029
7599
|
"LENB",
|
|
@@ -7216,6 +7786,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
7216
7786
|
"FACTDOUBLE": "SILNIA.DWUKR",
|
|
7217
7787
|
"FALSE": "FAŁSZ",
|
|
7218
7788
|
"FDIST": "ROZKŁAD.F",
|
|
7789
|
+
"FIELDVALUE": "POLE.WARTOŚĆ",
|
|
7219
7790
|
"FILTER": "FILTER",
|
|
7220
7791
|
"FILTERXML": "FILTERXML",
|
|
7221
7792
|
"FIND": "ZNAJDŹ",
|
|
@@ -7280,6 +7851,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
7280
7851
|
"IMLN": "LN.LICZBY.ZESP",
|
|
7281
7852
|
"IMLOG10": "LOG10.LICZBY.ZESP",
|
|
7282
7853
|
"IMLOG2": "LOG2.LICZBY.ZESP",
|
|
7854
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
7283
7855
|
"IMPOWER": "POTĘGA.LICZBY.ZESP",
|
|
7284
7856
|
"IMPRODUCT": "ILOCZYN.LICZB.ZESP",
|
|
7285
7857
|
"IMREAL": "CZ.RZECZ.LICZBY.ZESP",
|
|
@@ -7418,6 +7990,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
7418
7990
|
"PRODUCT": "ILOCZYN",
|
|
7419
7991
|
"PROPER": "Z.WIELKIEJ.LITERY",
|
|
7420
7992
|
"PV": "PV",
|
|
7993
|
+
"PY": "PY",
|
|
7421
7994
|
"QUARTILE": "KWARTYL",
|
|
7422
7995
|
"QUARTILE.EXC": "KWARTYL.PRZEDZ.OTW",
|
|
7423
7996
|
"QUARTILE.INC": "KWARTYL.PRZEDZ.ZAMK",
|
|
@@ -7579,6 +8152,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
7579
8152
|
},
|
|
7580
8153
|
"uncertain": [
|
|
7581
8154
|
"FINDB",
|
|
8155
|
+
"IMPORTTEXT",
|
|
7582
8156
|
"LEFTB",
|
|
7583
8157
|
"LENB",
|
|
7584
8158
|
"MIDB",
|
|
@@ -7770,6 +8344,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
7770
8344
|
"FACTDOUBLE": "FATDUPLO",
|
|
7771
8345
|
"FALSE": "FALSO",
|
|
7772
8346
|
"FDIST": "DISTF",
|
|
8347
|
+
"FIELDVALUE": "VALORDOCAMPO",
|
|
7773
8348
|
"FILTER": "FILTRAR",
|
|
7774
8349
|
"FILTERXML": "FILTRARXML",
|
|
7775
8350
|
"FIND": "LOCALIZAR",
|
|
@@ -7834,6 +8409,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
7834
8409
|
"IMLN": "IMLN",
|
|
7835
8410
|
"IMLOG10": "IMLOG10",
|
|
7836
8411
|
"IMLOG2": "IMLOG2",
|
|
8412
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
7837
8413
|
"IMPOWER": "IMPOT",
|
|
7838
8414
|
"IMPRODUCT": "IMPROD",
|
|
7839
8415
|
"IMREAL": "IMREAL",
|
|
@@ -7971,6 +8547,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
7971
8547
|
"PRODUCT": "PRODUTO",
|
|
7972
8548
|
"PROPER": "INICIAL.MAIÚSCULA",
|
|
7973
8549
|
"PV": "VA",
|
|
8550
|
+
"PY": "PY",
|
|
7974
8551
|
"QUARTILE": "QUARTIL",
|
|
7975
8552
|
"QUARTILE.EXC": "QUARTIL.EXC",
|
|
7976
8553
|
"QUARTILE.INC": "QUARTIL.INC",
|
|
@@ -8130,6 +8707,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
8130
8707
|
},
|
|
8131
8708
|
"uncertain": [
|
|
8132
8709
|
"FINDB",
|
|
8710
|
+
"IMPORTTEXT",
|
|
8133
8711
|
"JIS",
|
|
8134
8712
|
"LEFTB",
|
|
8135
8713
|
"LENB",
|
|
@@ -8322,6 +8900,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
8322
8900
|
"FACTDOUBLE": "FATDUPLO",
|
|
8323
8901
|
"FALSE": "FALSO",
|
|
8324
8902
|
"FDIST": "DISTF",
|
|
8903
|
+
"FIELDVALUE": "VALORCAMPO",
|
|
8325
8904
|
"FILTER": "FILTRO",
|
|
8326
8905
|
"FILTERXML": "FILTROXML",
|
|
8327
8906
|
"FIND": "PROCURAR",
|
|
@@ -8386,6 +8965,8 @@ const FORMULA_LOCALE_DATA = {
|
|
|
8386
8965
|
"IMLN": "IMLN",
|
|
8387
8966
|
"IMLOG10": "IMLOG10",
|
|
8388
8967
|
"IMLOG2": "IMLOG2",
|
|
8968
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
8969
|
+
"IMPORTTEXT": "IMPORTTEXT",
|
|
8389
8970
|
"IMPOWER": "IMPOT",
|
|
8390
8971
|
"IMPRODUCT": "IMPROD",
|
|
8391
8972
|
"IMREAL": "IMREAL",
|
|
@@ -8522,6 +9103,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
8522
9103
|
"PRODUCT": "MULT",
|
|
8523
9104
|
"PROPER": "PRI.MAIÚSCULA",
|
|
8524
9105
|
"PV": "VP",
|
|
9106
|
+
"PY": "PY",
|
|
8525
9107
|
"QUARTILE": "QUARTIL",
|
|
8526
9108
|
"QUARTILE.EXC": "QUARTIL.EXC",
|
|
8527
9109
|
"QUARTILE.INC": "QUARTIL.INC",
|
|
@@ -8864,6 +9446,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
8864
9446
|
"FACTDOUBLE": "ДВФАКТР",
|
|
8865
9447
|
"FALSE": "ЛОЖЬ",
|
|
8866
9448
|
"FDIST": "FРАСП",
|
|
9449
|
+
"FIELDVALUE": "ЗНАЧПОЛЯ",
|
|
8867
9450
|
"FILTER": "ФИЛЬТР",
|
|
8868
9451
|
"FILTERXML": "ФИЛЬТР.XML",
|
|
8869
9452
|
"FIND": "НАЙТИ",
|
|
@@ -8929,6 +9512,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
8929
9512
|
"IMLN": "МНИМ.LN",
|
|
8930
9513
|
"IMLOG10": "МНИМ.LOG10",
|
|
8931
9514
|
"IMLOG2": "МНИМ.LOG2",
|
|
9515
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
8932
9516
|
"IMPOWER": "МНИМ.СТЕПЕНЬ",
|
|
8933
9517
|
"IMPRODUCT": "МНИМ.ПРОИЗВЕД",
|
|
8934
9518
|
"IMREAL": "МНИМ.ВЕЩ",
|
|
@@ -9070,6 +9654,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
9070
9654
|
"PRODUCT": "ПРОИЗВЕД",
|
|
9071
9655
|
"PROPER": "ПРОПНАЧ",
|
|
9072
9656
|
"PV": "ПС",
|
|
9657
|
+
"PY": "PY",
|
|
9073
9658
|
"QUARTILE": "КВАРТИЛЬ",
|
|
9074
9659
|
"QUARTILE.EXC": "КВАРТИЛЬ.ИСКЛ",
|
|
9075
9660
|
"QUARTILE.INC": "КВАРТИЛЬ.ВКЛ",
|
|
@@ -9234,6 +9819,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
9234
9819
|
"#VALUE!": "#ЗНАЧ!"
|
|
9235
9820
|
},
|
|
9236
9821
|
"uncertain": [
|
|
9822
|
+
"IMPORTTEXT",
|
|
9237
9823
|
"SINGLE"
|
|
9238
9824
|
]
|
|
9239
9825
|
},
|
|
@@ -9419,6 +10005,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
9419
10005
|
"FACTDOUBLE": "ÇİFTFAKTÖR",
|
|
9420
10006
|
"FALSE": "YANLIŞ",
|
|
9421
10007
|
"FDIST": "FDAĞ",
|
|
10008
|
+
"FIELDVALUE": "FIELDVALUE",
|
|
9422
10009
|
"FILTER": "FİLTRE",
|
|
9423
10010
|
"FILTERXML": "XMLFİLTRELE",
|
|
9424
10011
|
"FIND": "BUL",
|
|
@@ -9483,6 +10070,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
9483
10070
|
"IMLN": "SANLN",
|
|
9484
10071
|
"IMLOG10": "SANLOG10",
|
|
9485
10072
|
"IMLOG2": "SANLOG2",
|
|
10073
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
9486
10074
|
"IMPOWER": "SANKUVVET",
|
|
9487
10075
|
"IMPRODUCT": "SANÇARP",
|
|
9488
10076
|
"IMREAL": "SANGERÇEK",
|
|
@@ -9621,6 +10209,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
9621
10209
|
"PRODUCT": "ÇARPIM",
|
|
9622
10210
|
"PROPER": "YAZIM.DÜZENİ",
|
|
9623
10211
|
"PV": "BD",
|
|
10212
|
+
"PY": "PY",
|
|
9624
10213
|
"QUARTILE": "DÖRTTEBİRLİK",
|
|
9625
10214
|
"QUARTILE.EXC": "DÖRTTEBİRLİK.HRC",
|
|
9626
10215
|
"QUARTILE.INC": "DÖRTTEBİRLİK.DHL",
|
|
@@ -9781,6 +10370,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
9781
10370
|
},
|
|
9782
10371
|
"uncertain": [
|
|
9783
10372
|
"FINDB",
|
|
10373
|
+
"IMPORTTEXT",
|
|
9784
10374
|
"LEFTB",
|
|
9785
10375
|
"LENB",
|
|
9786
10376
|
"MIDB",
|
|
@@ -31546,6 +32136,19 @@ const unavailable = () => {
|
|
|
31546
32136
|
throw FormulaError.NA;
|
|
31547
32137
|
};
|
|
31548
32138
|
|
|
32139
|
+
// The file imports (IMPORTTEXT, IMPORTCSV) and Python in Excel (PY) need a capability this engine
|
|
32140
|
+
// blocks (local files, a Python runtime): Excel reports that as #BLOCKED!. Linked data type fields
|
|
32141
|
+
// (FIELDVALUE, and `_FV` — `A1.Price` as a workbook file stores it) have no linked data types to
|
|
32142
|
+
// read here: #FIELD!, as Excel answers for a field the value does not have. Same answers as the
|
|
32143
|
+
// rnc engine (formualizer `builtins/external.rs`), so these are never #NAME? on either engine
|
|
32144
|
+
// (demo-app-monorepo#49969 FX-15).
|
|
32145
|
+
const blocked = () => {
|
|
32146
|
+
throw FormulaError.BLOCKED;
|
|
32147
|
+
};
|
|
32148
|
+
const noField = () => {
|
|
32149
|
+
throw FormulaError.FIELD;
|
|
32150
|
+
};
|
|
32151
|
+
|
|
31549
32152
|
const ExternalFunctions = {
|
|
31550
32153
|
CUBEKPIMEMBER: unavailable,
|
|
31551
32154
|
CUBEMEMBER: unavailable,
|
|
@@ -31562,6 +32165,11 @@ const ExternalFunctions = {
|
|
|
31562
32165
|
TRANSLATE: unavailable,
|
|
31563
32166
|
DETECTLANGUAGE: unavailable,
|
|
31564
32167
|
QUERY: unavailable,
|
|
32168
|
+
IMPORTTEXT: blocked,
|
|
32169
|
+
IMPORTCSV: blocked,
|
|
32170
|
+
PY: blocked,
|
|
32171
|
+
FIELDVALUE: noField,
|
|
32172
|
+
_FV: noField,
|
|
31565
32173
|
};
|
|
31566
32174
|
|
|
31567
32175
|
var api$3 = {};
|