@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/cjs/index.js
CHANGED
|
@@ -705,7 +705,9 @@ const excelNumberPrePass = (pattern, value, l10n, render) => {
|
|
|
705
705
|
if (!info)
|
|
706
706
|
return { value };
|
|
707
707
|
if (info.kind === "date") {
|
|
708
|
-
|
|
708
|
+
// A negative date or time — an elapsed `[h]:mm` duration included —
|
|
709
|
+
// shows `#######` in Excel's 1900 date system.
|
|
710
|
+
if (info.isElapsed && sections.length === 1 && value >= 0)
|
|
709
711
|
return { value };
|
|
710
712
|
if (value < 0 || value >= MAX_DATE_SERIAL_EXCLUSIVE) {
|
|
711
713
|
return { text: DATE_OVERFLOW_DISPLAY, value };
|
|
@@ -720,6 +722,16 @@ const excelNumberPrePass = (pattern, value, l10n, render) => {
|
|
|
720
722
|
if (index === 1 && value < 0 && pre.text === undefined && pre.value === 0) {
|
|
721
723
|
return { text: render(sections[index], 0), value };
|
|
722
724
|
}
|
|
725
|
+
// A one-section format keeps the minus of a negative that rounds to zero:
|
|
726
|
+
// Excel shows -0.4 in `0` as `-0` (and -0.004 in `0.00` as `-0.00`).
|
|
727
|
+
if (index === 0 &&
|
|
728
|
+
implicitSign &&
|
|
729
|
+
value < 0 &&
|
|
730
|
+
info.kind === "number" &&
|
|
731
|
+
pre.text === undefined &&
|
|
732
|
+
pre.value === 0) {
|
|
733
|
+
return { text: `-${render(sections[0], 0)}`, value };
|
|
734
|
+
}
|
|
723
735
|
return pre;
|
|
724
736
|
};
|
|
725
737
|
|
|
@@ -3805,6 +3817,500 @@ function isDateFormat (pattern) {
|
|
|
3805
3817
|
return isDate(data.partitions);
|
|
3806
3818
|
}
|
|
3807
3819
|
|
|
3820
|
+
/**
|
|
3821
|
+
* East Asian number-format tokens `numfmt` does not render: the `[DBNum1]`–`[DBNum4]` numeral
|
|
3822
|
+
* systems, the Japanese emperor-era tokens (`g`/`gg`/`ggg`, and `e`/`ee` under a Japanese locale)
|
|
3823
|
+
* and the `aaa`/`aaaa` weekday tokens. TypeScript twin of the engine's Rust
|
|
3824
|
+
* `rnc-cellmodel/src/cjk_format.rs` — keep the two in step.
|
|
3825
|
+
*
|
|
3826
|
+
* {@link prepareCjkNumberFormat} rewrites a format code so the base formatter can render it (era
|
|
3827
|
+
* names, era years and weekday names become quoted literals computed from the date serial,
|
|
3828
|
+
* `[DBNumN]` is removed, and under `[DBNumN]` a date's year becomes a quoted literal in that numeral
|
|
3829
|
+
* system); `finish` then turns the remaining ASCII digits into the numeral system:
|
|
3830
|
+
*
|
|
3831
|
+
* - `General` and date fields read as a number with units (`123` → `百二十三`, `15日` → `十五日`);
|
|
3832
|
+
* - digit placeholders (`0`, `#`) and years read digit by digit (`[DBNum1]0` → `一二三`).
|
|
3833
|
+
*
|
|
3834
|
+
* The language comes from the code's `[$-LCID]` / `[$-tag]` token, then the workbook locale, and
|
|
3835
|
+
* defaults to Japanese.
|
|
3836
|
+
*/
|
|
3837
|
+
const DBNUM_TOKEN = /^\[dbnum([1-4])\]$/i;
|
|
3838
|
+
/** Cheap pre-filter: a `DBNum` token, a `g` (era name or `General`), `aaa`, or an `e` beside a locale token. */
|
|
3839
|
+
const mightContainTokens = (code) => /[gG]|dbnum|aaa/i.test(code) || (/[eE]/.test(code) && code.includes("[$"));
|
|
3840
|
+
const prepareCjkNumberFormat = (code, value, workbookLocale) => {
|
|
3841
|
+
if (!mightContainTokens(code))
|
|
3842
|
+
return undefined;
|
|
3843
|
+
const tag = localeTag(code);
|
|
3844
|
+
const tagLang = tag ? cjkLangOfTag(tag) : undefined;
|
|
3845
|
+
const lang = tagLang ??
|
|
3846
|
+
(workbookLocale ? cjkLangOfTag(workbookLocale) : undefined) ??
|
|
3847
|
+
"ja";
|
|
3848
|
+
const gannen = !!tag && tag.toLowerCase().includes("-x-gannen");
|
|
3849
|
+
const date = serialToDate(value);
|
|
3850
|
+
const sections = splitFormatSections(code);
|
|
3851
|
+
const rewritten = [];
|
|
3852
|
+
const levels = [];
|
|
3853
|
+
const dated = [];
|
|
3854
|
+
let changed = false;
|
|
3855
|
+
for (const section of sections) {
|
|
3856
|
+
const level = dbnumLevel(section);
|
|
3857
|
+
const result = rewriteSection(section, {
|
|
3858
|
+
dbnum: level === undefined ? undefined : { level, lang },
|
|
3859
|
+
weekdayLang: lang,
|
|
3860
|
+
eraYears: tagLang === "ja" || hasEraNameToken(section),
|
|
3861
|
+
gannen,
|
|
3862
|
+
date,
|
|
3863
|
+
});
|
|
3864
|
+
changed ||= result.changed || level !== undefined;
|
|
3865
|
+
rewritten.push(result.text);
|
|
3866
|
+
levels.push(level);
|
|
3867
|
+
dated.push(result.dateToken);
|
|
3868
|
+
}
|
|
3869
|
+
if (!changed)
|
|
3870
|
+
return undefined;
|
|
3871
|
+
const anyCondition = sections.some((s) => analyzeFormatSection(s).hasCondition);
|
|
3872
|
+
const index = anyCondition
|
|
3873
|
+
? 0
|
|
3874
|
+
: Math.min(pickNumberSection(sections.length, value).index, sections.length - 1);
|
|
3875
|
+
const level = levels[index];
|
|
3876
|
+
const dbnum = level !== undefined && (level <= 3 || (level === 4 && lang === "ko"))
|
|
3877
|
+
? { level, lang }
|
|
3878
|
+
: undefined;
|
|
3879
|
+
let mode;
|
|
3880
|
+
if (dated[index]) {
|
|
3881
|
+
mode = "date";
|
|
3882
|
+
}
|
|
3883
|
+
else {
|
|
3884
|
+
switch (analyzeFormatSection(stripDbNum(sections[index])).kind) {
|
|
3885
|
+
case "general":
|
|
3886
|
+
mode = "general";
|
|
3887
|
+
break;
|
|
3888
|
+
case "date":
|
|
3889
|
+
mode = "date";
|
|
3890
|
+
break;
|
|
3891
|
+
case "number":
|
|
3892
|
+
case "other":
|
|
3893
|
+
mode = "digits";
|
|
3894
|
+
break;
|
|
3895
|
+
default:
|
|
3896
|
+
mode = "unchanged";
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
3899
|
+
return {
|
|
3900
|
+
code: rewritten.join(";"),
|
|
3901
|
+
finish: (out) => dbnum && mode !== "unchanged" ? convertDigits(out, dbnum, mode) : out,
|
|
3902
|
+
};
|
|
3903
|
+
};
|
|
3904
|
+
const runLength = (chars, from, letter) => {
|
|
3905
|
+
let n = 0;
|
|
3906
|
+
while (from + n < chars.length && chars[from + n].toLowerCase() === letter)
|
|
3907
|
+
n += 1;
|
|
3908
|
+
return n;
|
|
3909
|
+
};
|
|
3910
|
+
const startsWithCi = (chars, from, word) => chars
|
|
3911
|
+
.slice(from, from + word.length)
|
|
3912
|
+
.join("")
|
|
3913
|
+
.toLowerCase() === word;
|
|
3914
|
+
const quote = (text) => `"${text}"`;
|
|
3915
|
+
const rewriteSection = (section, ctx) => {
|
|
3916
|
+
const chars = Array.from(section);
|
|
3917
|
+
let out = "";
|
|
3918
|
+
let changed = false;
|
|
3919
|
+
let dateToken = false;
|
|
3920
|
+
let i = 0;
|
|
3921
|
+
while (i < chars.length) {
|
|
3922
|
+
const c = chars[i];
|
|
3923
|
+
const lower = c.toLowerCase();
|
|
3924
|
+
if (c === '"') {
|
|
3925
|
+
const close = chars.indexOf('"', i + 1);
|
|
3926
|
+
const end = close === -1 ? chars.length : close + 1;
|
|
3927
|
+
out += chars.slice(i, end).join("");
|
|
3928
|
+
i = end;
|
|
3929
|
+
}
|
|
3930
|
+
else if (c === "\\" || c === "_" || c === "*") {
|
|
3931
|
+
out += chars.slice(i, i + 2).join("");
|
|
3932
|
+
i += 2;
|
|
3933
|
+
}
|
|
3934
|
+
else if (c === "[") {
|
|
3935
|
+
const close = chars.indexOf("]", i);
|
|
3936
|
+
const end = close === -1 ? chars.length : close + 1;
|
|
3937
|
+
const token = chars.slice(i, end).join("");
|
|
3938
|
+
if (DBNUM_TOKEN.test(token))
|
|
3939
|
+
changed = true;
|
|
3940
|
+
else
|
|
3941
|
+
out += token;
|
|
3942
|
+
i = end;
|
|
3943
|
+
}
|
|
3944
|
+
else if (lower === "g" && startsWithCi(chars, i, "general")) {
|
|
3945
|
+
out += chars.slice(i, i + 7).join("");
|
|
3946
|
+
i += 7;
|
|
3947
|
+
}
|
|
3948
|
+
else if (lower === "g") {
|
|
3949
|
+
const run = runLength(chars, i, "g");
|
|
3950
|
+
if (ctx.date) {
|
|
3951
|
+
const era = eraOf(ctx.date);
|
|
3952
|
+
out += quote(run === 1 ? era.letter : run === 2 ? era.short : era.name);
|
|
3953
|
+
}
|
|
3954
|
+
changed = true;
|
|
3955
|
+
dateToken = true;
|
|
3956
|
+
i += run;
|
|
3957
|
+
}
|
|
3958
|
+
else if (lower === "e" && chars[i + 1] !== "+" && chars[i + 1] !== "-") {
|
|
3959
|
+
const run = runLength(chars, i, "e");
|
|
3960
|
+
if (ctx.date && ctx.eraYears) {
|
|
3961
|
+
const eraYear = ctx.date.year - eraOf(ctx.date).start[0] + 1;
|
|
3962
|
+
const text = eraYear === 1 && ctx.gannen
|
|
3963
|
+
? "元"
|
|
3964
|
+
: run >= 2
|
|
3965
|
+
? String(eraYear).padStart(2, "0")
|
|
3966
|
+
: String(eraYear);
|
|
3967
|
+
out += quote(text);
|
|
3968
|
+
changed = true;
|
|
3969
|
+
dateToken = true;
|
|
3970
|
+
}
|
|
3971
|
+
else if (ctx.date && ctx.dbnum) {
|
|
3972
|
+
out += quote(perDigit(String(ctx.date.year), ctx.dbnum));
|
|
3973
|
+
changed = true;
|
|
3974
|
+
dateToken = true;
|
|
3975
|
+
}
|
|
3976
|
+
else {
|
|
3977
|
+
out += chars.slice(i, i + run).join("");
|
|
3978
|
+
}
|
|
3979
|
+
i += run;
|
|
3980
|
+
}
|
|
3981
|
+
else if (lower === "a" && startsWithCi(chars, i, "am/pm")) {
|
|
3982
|
+
out += chars.slice(i, i + 5).join("");
|
|
3983
|
+
i += 5;
|
|
3984
|
+
}
|
|
3985
|
+
else if (lower === "a" && startsWithCi(chars, i, "a/p")) {
|
|
3986
|
+
out += chars.slice(i, i + 3).join("");
|
|
3987
|
+
i += 3;
|
|
3988
|
+
}
|
|
3989
|
+
else if (lower === "a" && runLength(chars, i, "a") >= 3) {
|
|
3990
|
+
const run = runLength(chars, i, "a");
|
|
3991
|
+
if (ctx.date)
|
|
3992
|
+
out += quote(weekdayName(ctx.weekdayLang, ctx.date.weekday, run >= 4));
|
|
3993
|
+
changed = true;
|
|
3994
|
+
dateToken = true;
|
|
3995
|
+
i += run;
|
|
3996
|
+
}
|
|
3997
|
+
else if (lower === "y" && ctx.dbnum && ctx.date) {
|
|
3998
|
+
const run = runLength(chars, i, "y");
|
|
3999
|
+
const digits = run <= 2
|
|
4000
|
+
? String(ctx.date.year % 100).padStart(2, "0")
|
|
4001
|
+
: String(ctx.date.year);
|
|
4002
|
+
out += quote(perDigit(digits, ctx.dbnum));
|
|
4003
|
+
changed = true;
|
|
4004
|
+
dateToken = true;
|
|
4005
|
+
i += run;
|
|
4006
|
+
}
|
|
4007
|
+
else {
|
|
4008
|
+
out += c;
|
|
4009
|
+
i += 1;
|
|
4010
|
+
}
|
|
4011
|
+
}
|
|
4012
|
+
return { text: out, changed, dateToken };
|
|
4013
|
+
};
|
|
4014
|
+
/** `[...]` tokens outside quoted literals and escapes. */
|
|
4015
|
+
const bracketTokens = (section) => {
|
|
4016
|
+
const tokens = [];
|
|
4017
|
+
let inQuotes = false;
|
|
4018
|
+
for (let i = 0; i < section.length; i += 1) {
|
|
4019
|
+
const c = section[i];
|
|
4020
|
+
if (c === '"')
|
|
4021
|
+
inQuotes = !inQuotes;
|
|
4022
|
+
else if (!inQuotes && (c === "\\" || c === "_" || c === "*"))
|
|
4023
|
+
i += 1;
|
|
4024
|
+
else if (!inQuotes && c === "[") {
|
|
4025
|
+
const end = section.indexOf("]", i);
|
|
4026
|
+
if (end !== -1) {
|
|
4027
|
+
tokens.push(section.slice(i, end + 1));
|
|
4028
|
+
i = end;
|
|
4029
|
+
}
|
|
4030
|
+
}
|
|
4031
|
+
}
|
|
4032
|
+
return tokens;
|
|
4033
|
+
};
|
|
4034
|
+
const dbnumLevel = (section) => {
|
|
4035
|
+
for (const token of bracketTokens(section)) {
|
|
4036
|
+
const m = DBNUM_TOKEN.exec(token);
|
|
4037
|
+
if (m)
|
|
4038
|
+
return Number(m[1]);
|
|
4039
|
+
}
|
|
4040
|
+
return undefined;
|
|
4041
|
+
};
|
|
4042
|
+
const stripDbNum = (section) => bracketTokens(section)
|
|
4043
|
+
.filter((t) => DBNUM_TOKEN.test(t))
|
|
4044
|
+
.reduce((s, t) => s.replace(t, ""), section);
|
|
4045
|
+
/** Whether a section names an era (`g`) outside quotes, brackets and `General`. */
|
|
4046
|
+
const hasEraNameToken = (section) => {
|
|
4047
|
+
let inQuotes = false;
|
|
4048
|
+
let inBrackets = false;
|
|
4049
|
+
for (let i = 0; i < section.length; i += 1) {
|
|
4050
|
+
const c = section[i];
|
|
4051
|
+
if (inQuotes)
|
|
4052
|
+
inQuotes = c !== '"';
|
|
4053
|
+
else if (inBrackets)
|
|
4054
|
+
inBrackets = c !== "]";
|
|
4055
|
+
else if (c === '"')
|
|
4056
|
+
inQuotes = true;
|
|
4057
|
+
else if (c === "[")
|
|
4058
|
+
inBrackets = true;
|
|
4059
|
+
else if (c === "\\" || c === "_" || c === "*")
|
|
4060
|
+
i += 1;
|
|
4061
|
+
else if (c.toLowerCase() === "g") {
|
|
4062
|
+
if (section.slice(i, i + 7).toLowerCase() === "general")
|
|
4063
|
+
i += 6;
|
|
4064
|
+
else
|
|
4065
|
+
return true;
|
|
4066
|
+
}
|
|
4067
|
+
}
|
|
4068
|
+
return false;
|
|
4069
|
+
};
|
|
4070
|
+
/** The locale spec of the code's first `[$…-spec]` token (`411`, `ja-JP`, `ja-JP-x-gannen`). */
|
|
4071
|
+
const localeTag = (code) => {
|
|
4072
|
+
const start = code.indexOf("[$");
|
|
4073
|
+
if (start === -1)
|
|
4074
|
+
return undefined;
|
|
4075
|
+
const end = code.indexOf("]", start);
|
|
4076
|
+
if (end === -1)
|
|
4077
|
+
return undefined;
|
|
4078
|
+
const inner = code.slice(start + 2, end);
|
|
4079
|
+
const dash = inner.indexOf("-");
|
|
4080
|
+
if (dash === -1)
|
|
4081
|
+
return undefined;
|
|
4082
|
+
const spec = inner.slice(dash + 1);
|
|
4083
|
+
return spec || undefined;
|
|
4084
|
+
};
|
|
4085
|
+
/** Language of an LCID (hex, low 16 bits) or a BCP-47 tag, for the CJK locales. */
|
|
4086
|
+
const cjkLangOfTag = (input) => {
|
|
4087
|
+
const spec = input.split(",")[0].trim();
|
|
4088
|
+
if (/^[0-9a-f]+$/i.test(spec)) {
|
|
4089
|
+
switch (parseInt(spec, 16) & 0xffff) {
|
|
4090
|
+
case 0x0411:
|
|
4091
|
+
return "ja";
|
|
4092
|
+
case 0x0804:
|
|
4093
|
+
case 0x1004:
|
|
4094
|
+
return "zh-Hans";
|
|
4095
|
+
case 0x0404:
|
|
4096
|
+
case 0x0c04:
|
|
4097
|
+
case 0x1404:
|
|
4098
|
+
return "zh-Hant";
|
|
4099
|
+
case 0x0412:
|
|
4100
|
+
return "ko";
|
|
4101
|
+
default:
|
|
4102
|
+
return undefined;
|
|
4103
|
+
}
|
|
4104
|
+
}
|
|
4105
|
+
const [primary, ...rest] = spec.toLowerCase().split(/[-_]/);
|
|
4106
|
+
if (primary === "ja")
|
|
4107
|
+
return "ja";
|
|
4108
|
+
if (primary === "ko")
|
|
4109
|
+
return "ko";
|
|
4110
|
+
if (primary === "zh") {
|
|
4111
|
+
return rest.some((p) => p === "hant" || p === "tw" || p === "hk" || p === "mo")
|
|
4112
|
+
? "zh-Hant"
|
|
4113
|
+
: "zh-Hans";
|
|
4114
|
+
}
|
|
4115
|
+
return undefined;
|
|
4116
|
+
};
|
|
4117
|
+
// ---- dates ------------------------------------------------------------------------------------
|
|
4118
|
+
/**
|
|
4119
|
+
* Excel 1900-system serial → calendar date, keeping Excel's fictitious 1900-02-29 (serial 60)
|
|
4120
|
+
* and its weekday numbering (serial 1 is a Sunday). The time of day rounds to the nearest second.
|
|
4121
|
+
*/
|
|
4122
|
+
const serialToDate = (value) => {
|
|
4123
|
+
if (!Number.isFinite(value) || value < 0 || value >= 2958466)
|
|
4124
|
+
return undefined;
|
|
4125
|
+
const days = Math.floor(Math.round(value * 86400) / 86400);
|
|
4126
|
+
const weekday = (days + 6) % 7;
|
|
4127
|
+
if (days === 60)
|
|
4128
|
+
return { year: 1900, month: 2, day: 29, weekday };
|
|
4129
|
+
const offset = days < 60 ? days : days - 1;
|
|
4130
|
+
const d = new Date(Date.UTC(1899, 11, 31) + offset * 86400000);
|
|
4131
|
+
return {
|
|
4132
|
+
year: d.getUTCFullYear(),
|
|
4133
|
+
month: d.getUTCMonth() + 1,
|
|
4134
|
+
day: d.getUTCDate(),
|
|
4135
|
+
weekday,
|
|
4136
|
+
};
|
|
4137
|
+
};
|
|
4138
|
+
/** Japanese eras with the start dates Windows' Japanese calendar (and so Excel) uses. */
|
|
4139
|
+
const ERAS = [
|
|
4140
|
+
{ start: [1868, 1, 1], letter: "M", short: "明", name: "明治" },
|
|
4141
|
+
{ start: [1912, 7, 30], letter: "T", short: "大", name: "大正" },
|
|
4142
|
+
{ start: [1926, 12, 25], letter: "S", short: "昭", name: "昭和" },
|
|
4143
|
+
{ start: [1989, 1, 8], letter: "H", short: "平", name: "平成" },
|
|
4144
|
+
{ start: [2019, 5, 1], letter: "R", short: "令", name: "令和" },
|
|
4145
|
+
];
|
|
4146
|
+
const eraOf = (date) => {
|
|
4147
|
+
const key = date.year * 10000 + date.month * 100 + date.day;
|
|
4148
|
+
for (let i = ERAS.length - 1; i >= 0; i -= 1) {
|
|
4149
|
+
const [y, m, d] = ERAS[i].start;
|
|
4150
|
+
if (key >= y * 10000 + m * 100 + d)
|
|
4151
|
+
return ERAS[i];
|
|
4152
|
+
}
|
|
4153
|
+
return ERAS[0];
|
|
4154
|
+
};
|
|
4155
|
+
const weekdayName = (lang, weekday, long) => {
|
|
4156
|
+
const w = weekday % 7;
|
|
4157
|
+
switch (lang) {
|
|
4158
|
+
case "ja": {
|
|
4159
|
+
const short = "日月火水木金土"[w];
|
|
4160
|
+
return long ? `${short}曜日` : short;
|
|
4161
|
+
}
|
|
4162
|
+
case "ko": {
|
|
4163
|
+
const short = "일월화수목금토"[w];
|
|
4164
|
+
return long ? `${short}요일` : short;
|
|
4165
|
+
}
|
|
4166
|
+
default: {
|
|
4167
|
+
const short = "日一二三四五六"[w];
|
|
4168
|
+
return long ? `星期${short}` : short;
|
|
4169
|
+
}
|
|
4170
|
+
}
|
|
4171
|
+
};
|
|
4172
|
+
const KANJI = Array.from("〇一二三四五六七八九");
|
|
4173
|
+
const FULL_WIDTH = Array.from("0123456789");
|
|
4174
|
+
const BIG_HANS = ["万", "亿", "兆"];
|
|
4175
|
+
const BIG_TRAD = ["萬", "億", "兆"];
|
|
4176
|
+
const BIG_JA = ["万", "億", "兆"];
|
|
4177
|
+
const numerals = ({ level, lang }) => {
|
|
4178
|
+
const zh = lang === "zh-Hans" || lang === "zh-Hant";
|
|
4179
|
+
const level1Big = lang === "ja" ? BIG_JA : lang === "zh-Hans" ? BIG_HANS : BIG_TRAD;
|
|
4180
|
+
if (level === 2) {
|
|
4181
|
+
switch (lang) {
|
|
4182
|
+
case "ja":
|
|
4183
|
+
return {
|
|
4184
|
+
digits: Array.from("〇壱弐参四伍六七八九"),
|
|
4185
|
+
small: ["拾", "百", "阡"],
|
|
4186
|
+
big: BIG_TRAD,
|
|
4187
|
+
omitOne: false,
|
|
4188
|
+
fillZero: false,
|
|
4189
|
+
};
|
|
4190
|
+
case "zh-Hans":
|
|
4191
|
+
return {
|
|
4192
|
+
digits: Array.from("零壹贰叁肆伍陆柒捌玖"),
|
|
4193
|
+
small: ["拾", "佰", "仟"],
|
|
4194
|
+
big: BIG_HANS,
|
|
4195
|
+
omitOne: false,
|
|
4196
|
+
fillZero: true,
|
|
4197
|
+
};
|
|
4198
|
+
case "zh-Hant":
|
|
4199
|
+
return {
|
|
4200
|
+
digits: Array.from("零壹貳參肆伍陸柒捌玖"),
|
|
4201
|
+
small: ["拾", "佰", "仟"],
|
|
4202
|
+
big: BIG_TRAD,
|
|
4203
|
+
omitOne: false,
|
|
4204
|
+
fillZero: true,
|
|
4205
|
+
};
|
|
4206
|
+
case "ko":
|
|
4207
|
+
return {
|
|
4208
|
+
digits: Array.from("零壹貳參四伍六七八九"),
|
|
4209
|
+
small: ["拾", "百", "阡"],
|
|
4210
|
+
big: BIG_TRAD,
|
|
4211
|
+
omitOne: false,
|
|
4212
|
+
fillZero: false,
|
|
4213
|
+
};
|
|
4214
|
+
}
|
|
4215
|
+
}
|
|
4216
|
+
if (level === 3) {
|
|
4217
|
+
return {
|
|
4218
|
+
digits: FULL_WIDTH,
|
|
4219
|
+
small: ["十", "百", "千"],
|
|
4220
|
+
big: level1Big,
|
|
4221
|
+
omitOne: false,
|
|
4222
|
+
fillZero: zh,
|
|
4223
|
+
};
|
|
4224
|
+
}
|
|
4225
|
+
if (level === 4 && lang === "ko") {
|
|
4226
|
+
return {
|
|
4227
|
+
digits: Array.from("영일이삼사오육칠팔구"),
|
|
4228
|
+
small: ["십", "백", "천"],
|
|
4229
|
+
big: ["만", "억", "조"],
|
|
4230
|
+
omitOne: true,
|
|
4231
|
+
fillZero: false,
|
|
4232
|
+
};
|
|
4233
|
+
}
|
|
4234
|
+
return {
|
|
4235
|
+
digits: KANJI,
|
|
4236
|
+
small: ["十", "百", "千"],
|
|
4237
|
+
big: level1Big,
|
|
4238
|
+
omitOne: !zh,
|
|
4239
|
+
fillZero: zh,
|
|
4240
|
+
};
|
|
4241
|
+
};
|
|
4242
|
+
const perDigit = (digits, dbnum) => {
|
|
4243
|
+
const table = numerals(dbnum).digits;
|
|
4244
|
+
return Array.from(digits)
|
|
4245
|
+
.map((c) => (c >= "0" && c <= "9" ? table[Number(c)] : c))
|
|
4246
|
+
.join("");
|
|
4247
|
+
};
|
|
4248
|
+
/** `digits` read as a number with units; past 兆 (≥ 10^16) digit by digit. */
|
|
4249
|
+
const withUnits = (digits, dbnum) => {
|
|
4250
|
+
const n = numerals(dbnum);
|
|
4251
|
+
const trimmed = digits.replace(/^0+/, "");
|
|
4252
|
+
if (!trimmed)
|
|
4253
|
+
return n.digits[0];
|
|
4254
|
+
if (trimmed.length > 16)
|
|
4255
|
+
return perDigit(digits, dbnum);
|
|
4256
|
+
const values = Array.from(trimmed, Number);
|
|
4257
|
+
const groups = Math.ceil(values.length / 4);
|
|
4258
|
+
let out = "";
|
|
4259
|
+
let pendingZero = false;
|
|
4260
|
+
for (let g = 0; g < groups; g += 1) {
|
|
4261
|
+
const groupIndex = groups - 1 - g;
|
|
4262
|
+
const end = values.length - groupIndex * 4;
|
|
4263
|
+
const group = values.slice(Math.max(0, end - 4), end);
|
|
4264
|
+
let wrote = false;
|
|
4265
|
+
group.forEach((d, k) => {
|
|
4266
|
+
const pos = group.length - 1 - k;
|
|
4267
|
+
if (d === 0) {
|
|
4268
|
+
pendingZero ||= out.length > 0 || wrote;
|
|
4269
|
+
return;
|
|
4270
|
+
}
|
|
4271
|
+
if (pendingZero && n.fillZero)
|
|
4272
|
+
out += "零";
|
|
4273
|
+
pendingZero = false;
|
|
4274
|
+
if (!(d === 1 && pos > 0 && n.omitOne))
|
|
4275
|
+
out += n.digits[d];
|
|
4276
|
+
if (pos > 0)
|
|
4277
|
+
out += n.small[pos - 1];
|
|
4278
|
+
wrote = true;
|
|
4279
|
+
});
|
|
4280
|
+
if (wrote && groupIndex > 0)
|
|
4281
|
+
out += n.big[groupIndex - 1];
|
|
4282
|
+
}
|
|
4283
|
+
return out;
|
|
4284
|
+
};
|
|
4285
|
+
const isAsciiDigit = (c) => !!c && c >= "0" && c <= "9";
|
|
4286
|
+
const convertDigits = (text, dbnum, mode) => {
|
|
4287
|
+
const chars = Array.from(text);
|
|
4288
|
+
let out = "";
|
|
4289
|
+
let i = 0;
|
|
4290
|
+
while (i < chars.length) {
|
|
4291
|
+
if (!isAsciiDigit(chars[i])) {
|
|
4292
|
+
out += chars[i];
|
|
4293
|
+
i += 1;
|
|
4294
|
+
continue;
|
|
4295
|
+
}
|
|
4296
|
+
let end = i;
|
|
4297
|
+
while (end < chars.length && isAsciiDigit(chars[end]))
|
|
4298
|
+
end += 1;
|
|
4299
|
+
const run = chars.slice(i, end).join("");
|
|
4300
|
+
const fraction = i >= 2 &&
|
|
4301
|
+
(chars[i - 1] === "." || chars[i - 1] === ",") &&
|
|
4302
|
+
isAsciiDigit(chars[i - 2]);
|
|
4303
|
+
const units = mode === "date"
|
|
4304
|
+
? dbnum.level !== 3
|
|
4305
|
+
: mode === "general"
|
|
4306
|
+
? !fraction
|
|
4307
|
+
: false;
|
|
4308
|
+
out += units ? withUnits(run, dbnum) : perDigit(run, dbnum);
|
|
4309
|
+
i = end;
|
|
4310
|
+
}
|
|
4311
|
+
return out;
|
|
4312
|
+
};
|
|
4313
|
+
|
|
3808
4314
|
// Excel indexed colors mapping used for legacy color references
|
|
3809
4315
|
const IndexedColors = Object.freeze([
|
|
3810
4316
|
// 0-7
|
|
@@ -3881,35 +4387,44 @@ const IndexedColors = Object.freeze([
|
|
|
3881
4387
|
"#333333",
|
|
3882
4388
|
]);
|
|
3883
4389
|
|
|
3884
|
-
const isSingleSectionElapsedTimePattern = (pattern) => !pattern.includes(";") &&
|
|
3885
|
-
/\[(?:h+|m+|s+)\]/i.test(pattern.replace(/\[\$[^\]]+\]/g, ""));
|
|
3886
4390
|
const intlMonthNames = (locale, options) => {
|
|
3887
4391
|
const formatter = new Intl.DateTimeFormat(locale, {
|
|
3888
4392
|
...options,
|
|
3889
4393
|
timeZone: "UTC",
|
|
3890
4394
|
});
|
|
3891
|
-
|
|
3892
|
-
.formatToParts(new Date(Date.UTC(2020, month, 1)))
|
|
3893
|
-
.
|
|
4395
|
+
const names = Array.from({ length: 12 }, (_, month) => {
|
|
4396
|
+
const parts = formatter.formatToParts(new Date(Date.UTC(2020, month, 1)));
|
|
4397
|
+
const index = parts.findIndex((part) => part.type === "month");
|
|
4398
|
+
const name = parts[index]?.value ?? "";
|
|
4399
|
+
// A numeric month comes split from its counter ("1" + "月"); the CLDR
|
|
4400
|
+
// name on its own (what the Rust engine renders) is "1月".
|
|
4401
|
+
const next = parts[index + 1];
|
|
4402
|
+
return /^\d+$/.test(name) && next?.type === "literal" && !/\d/.test(next.value)
|
|
4403
|
+
? name + next.value.trim()
|
|
4404
|
+
: name;
|
|
4405
|
+
});
|
|
4406
|
+
// Beside a day, zh/ja write the month as a number ("3月15日") even where
|
|
4407
|
+
// CLDR's `MMMM` on its own is a word (zh "三月"): take the standalone name.
|
|
4408
|
+
if (options.day && names.every((name) => /^\d/.test(name))) {
|
|
4409
|
+
return intlMonthNames(locale, { month: options.month });
|
|
4410
|
+
}
|
|
4411
|
+
return names;
|
|
3894
4412
|
};
|
|
3895
4413
|
const intlRegisteredLocales = new Set();
|
|
3896
4414
|
/**
|
|
3897
|
-
*
|
|
3898
|
-
* (
|
|
3899
|
-
* separators
|
|
3900
|
-
*
|
|
3901
|
-
*
|
|
3902
|
-
*
|
|
3903
|
-
*
|
|
3904
|
-
* designators. Tags Intl itself does not know keep numfmt's fallback.
|
|
4415
|
+
* Every locale renders from a numfmt locale built from Intl (CLDR) the way the
|
|
4416
|
+
* Rust engine (the Excel reference, `rnc_cellmodel::locale_data`) builds its
|
|
4417
|
+
* own: separators from `Intl.NumberFormat`, the in-date month and weekday
|
|
4418
|
+
* names, and English `AM`/`PM` and `TRUE`/`FALSE` (numfmt's defaults), not
|
|
4419
|
+
* numfmt's shipped tables (de `WAHR`, ja `午前`, en-GB `Sep`). A month shown
|
|
4420
|
+
* without a day takes the standalone names (`getStandaloneMonthLocale`). Tags
|
|
4421
|
+
* Intl does not know keep numfmt's fallback.
|
|
3905
4422
|
*/
|
|
3906
4423
|
const ensureNumfmtLocale = (locale) => {
|
|
3907
4424
|
if (intlRegisteredLocales.has(locale))
|
|
3908
4425
|
return;
|
|
3909
4426
|
intlRegisteredLocales.add(locale);
|
|
3910
4427
|
try {
|
|
3911
|
-
if (getLocale(locale))
|
|
3912
|
-
return;
|
|
3913
4428
|
const canonical = Intl.DateTimeFormat.supportedLocalesOf([locale])[0];
|
|
3914
4429
|
if (!canonical)
|
|
3915
4430
|
return;
|
|
@@ -3928,20 +4443,11 @@ const ensureNumfmtLocale = (locale) => {
|
|
|
3928
4443
|
.formatToParts(new Date(Date.UTC(2024, 0, 7 + i)))
|
|
3929
4444
|
.find((p) => p.type === "weekday")?.value ?? "");
|
|
3930
4445
|
};
|
|
3931
|
-
const dayPeriod = (hour) => new Intl.DateTimeFormat(locale, {
|
|
3932
|
-
hour: "numeric",
|
|
3933
|
-
hour12: true,
|
|
3934
|
-
timeZone: "UTC",
|
|
3935
|
-
})
|
|
3936
|
-
.formatToParts(new Date(Date.UTC(2024, 0, 7, hour)))
|
|
3937
|
-
.find((p) => p.type === "dayPeriod")?.value;
|
|
3938
4446
|
const dateParts = new Intl.DateTimeFormat(locale, {
|
|
3939
4447
|
timeZone: "UTC",
|
|
3940
4448
|
}).formatToParts(new Date(Date.UTC(2024, 0, 7)));
|
|
3941
4449
|
const monthIndex = dateParts.findIndex((p) => p.type === "month");
|
|
3942
4450
|
const dayIndex = dateParts.findIndex((p) => p.type === "day");
|
|
3943
|
-
const am = dayPeriod(9);
|
|
3944
|
-
const pm = dayPeriod(21);
|
|
3945
4451
|
addLocale({
|
|
3946
4452
|
group: part("group") ?? "\u00a0",
|
|
3947
4453
|
decimal: part("decimal") ?? ".",
|
|
@@ -3949,7 +4455,6 @@ const ensureNumfmtLocale = (locale) => {
|
|
|
3949
4455
|
mmm: intlMonthNames(locale, { day: "numeric", month: "short" }),
|
|
3950
4456
|
dddd: weekdayNames("long"),
|
|
3951
4457
|
ddd: weekdayNames("short"),
|
|
3952
|
-
...(am && pm && am !== pm ? { ampm: [am, pm] } : {}),
|
|
3953
4458
|
preferMDY: monthIndex >= 0 && dayIndex >= 0 && monthIndex < dayIndex,
|
|
3954
4459
|
}, locale);
|
|
3955
4460
|
}
|
|
@@ -3957,6 +4462,31 @@ const ensureNumfmtLocale = (locale) => {
|
|
|
3957
4462
|
// Malformed tag: numfmt keeps its own fallback.
|
|
3958
4463
|
}
|
|
3959
4464
|
};
|
|
4465
|
+
const scientificLocales = new Map();
|
|
4466
|
+
/**
|
|
4467
|
+
* The Rust engine (ssfmt) renders a scientific mantissa with `.` in every
|
|
4468
|
+
* locale (`1.00E+03` in de-DE), so an exponent section renders under a
|
|
4469
|
+
* companion locale whose decimal separator is `.`.
|
|
4470
|
+
*/
|
|
4471
|
+
const getScientificLocale = (locale) => {
|
|
4472
|
+
const cached = scientificLocales.get(locale);
|
|
4473
|
+
if (cached !== undefined)
|
|
4474
|
+
return cached;
|
|
4475
|
+
let overlay = locale;
|
|
4476
|
+
try {
|
|
4477
|
+
const base = getLocale(locale);
|
|
4478
|
+
if (base && base.decimal !== ".") {
|
|
4479
|
+
overlay = `sci_${locale.replace(/[^a-z\d]/gi, "")}`;
|
|
4480
|
+
addLocale({ ...base, decimal: "." }, overlay);
|
|
4481
|
+
}
|
|
4482
|
+
}
|
|
4483
|
+
catch {
|
|
4484
|
+
overlay = locale;
|
|
4485
|
+
}
|
|
4486
|
+
scientificLocales.set(locale, overlay);
|
|
4487
|
+
return overlay;
|
|
4488
|
+
};
|
|
4489
|
+
const SCIENTIFIC_SECTION = /^(?:"[^"]*"|\[[^\]]*\]|\\.|[^"\[\\eE])*[eE][+-]/;
|
|
3960
4490
|
const localeForPattern = (pattern, locale) => {
|
|
3961
4491
|
return locale;
|
|
3962
4492
|
};
|
|
@@ -4207,6 +4737,17 @@ const withWorkbookSeparatorsCached = (code, locale) => {
|
|
|
4207
4737
|
return rewritten;
|
|
4208
4738
|
};
|
|
4209
4739
|
const ssfFormat = (pattern, value, locale) => {
|
|
4740
|
+
// East Asian tokens numfmt does not render (`[DBNumN]`, Japanese era `g`/`e`,
|
|
4741
|
+
// `aaa` weekdays): rewrite the code to plain literals, then convert the
|
|
4742
|
+
// rendered digits to the `[DBNumN]` numeral system (see cjk-number-format).
|
|
4743
|
+
if (typeof value === "number") {
|
|
4744
|
+
const cjk = prepareCjkNumberFormat(pattern, value, locale);
|
|
4745
|
+
if (cjk)
|
|
4746
|
+
return cjk.finish(ssfFormatBase(cjk.code, value, locale));
|
|
4747
|
+
}
|
|
4748
|
+
return ssfFormatBase(pattern, value, locale);
|
|
4749
|
+
};
|
|
4750
|
+
function ssfFormatBase(pattern, value, locale, layout) {
|
|
4210
4751
|
try {
|
|
4211
4752
|
if (locale)
|
|
4212
4753
|
;
|
|
@@ -4215,12 +4756,25 @@ const ssfFormat = (pattern, value, locale) => {
|
|
|
4215
4756
|
shortAmPm = withShortAmPmMarker(pattern);
|
|
4216
4757
|
shortAmPmPatternCache.set(pattern, shortAmPm);
|
|
4217
4758
|
}
|
|
4218
|
-
const
|
|
4759
|
+
const baseCode = withWorkbookSeparatorsCached(shortAmPm ?? pattern, locale);
|
|
4760
|
+
const code = layout ? layout.transform(baseCode) : baseCode;
|
|
4219
4761
|
let patternLocale = localeForPattern(pattern, locale);
|
|
4762
|
+
if (patternLocale && SCIENTIFIC_SECTION.test(pattern)) {
|
|
4763
|
+
patternLocale = getScientificLocale(patternLocale);
|
|
4764
|
+
}
|
|
4220
4765
|
if (shortAmPm !== undefined && patternLocale) {
|
|
4221
4766
|
patternLocale = getShortAmPmLocale(patternLocale);
|
|
4222
4767
|
}
|
|
4223
|
-
|
|
4768
|
+
// numfmt types `fillChar` / `skipChar` as booleans; at runtime they are
|
|
4769
|
+
// the marker strings it emits ahead of the fill / skip character.
|
|
4770
|
+
const options = layout
|
|
4771
|
+
? {
|
|
4772
|
+
locale: patternLocale,
|
|
4773
|
+
nbsp: layout.nbsp,
|
|
4774
|
+
fillChar: layout.fillChar,
|
|
4775
|
+
skipChar: layout.skipChar,
|
|
4776
|
+
}
|
|
4777
|
+
: { locale: patternLocale };
|
|
4224
4778
|
if (typeof value === "number") {
|
|
4225
4779
|
// Excel decides rounding, `General`, huge magnitudes and conditional
|
|
4226
4780
|
// sections from the 15-significant-digit decimal, not the binary
|
|
@@ -4231,16 +4785,12 @@ const ssfFormat = (pattern, value, locale) => {
|
|
|
4231
4785
|
}
|
|
4232
4786
|
value = pre.value;
|
|
4233
4787
|
}
|
|
4234
|
-
|
|
4235
|
-
value < 0 &&
|
|
4236
|
-
isSingleSectionElapsedTimePattern(pattern);
|
|
4237
|
-
const formatted = format(code, isNegativeElapsedTime ? Math.abs(value) : value, options);
|
|
4238
|
-
return isNegativeElapsedTime ? `-${formatted}` : formatted;
|
|
4788
|
+
return format(code, value, options);
|
|
4239
4789
|
}
|
|
4240
4790
|
catch (err) {
|
|
4241
|
-
return String(value);
|
|
4791
|
+
return layout ? undefined : String(value);
|
|
4242
4792
|
}
|
|
4243
|
-
}
|
|
4793
|
+
}
|
|
4244
4794
|
for (let n = 1; n <= 56; n++) {
|
|
4245
4795
|
IndexedColors[n + 7];
|
|
4246
4796
|
}
|
|
@@ -4433,6 +4983,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
4433
4983
|
"FACTDOUBLE": "ZWEIFAKULTÄT",
|
|
4434
4984
|
"FALSE": "FALSCH",
|
|
4435
4985
|
"FDIST": "FVERT",
|
|
4986
|
+
"FIELDVALUE": "FELDWERT",
|
|
4436
4987
|
"FILTER": "FILTER",
|
|
4437
4988
|
"FILTERXML": "XMLFILTERN",
|
|
4438
4989
|
"FIND": "FINDEN",
|
|
@@ -4496,6 +5047,8 @@ const FORMULA_LOCALE_DATA = {
|
|
|
4496
5047
|
"IMLN": "IMLN",
|
|
4497
5048
|
"IMLOG10": "IMLOG10",
|
|
4498
5049
|
"IMLOG2": "IMLOG2",
|
|
5050
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
5051
|
+
"IMPORTTEXT": "IMPORTTEXT",
|
|
4499
5052
|
"IMPOWER": "IMAPOTENZ",
|
|
4500
5053
|
"IMPRODUCT": "IMPRODUKT",
|
|
4501
5054
|
"IMREAL": "IMREALTEIL",
|
|
@@ -4633,6 +5186,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
4633
5186
|
"PRODUCT": "PRODUKT",
|
|
4634
5187
|
"PROPER": "GROSS2",
|
|
4635
5188
|
"PV": "BW",
|
|
5189
|
+
"PY": "PY",
|
|
4636
5190
|
"QUARTILE": "QUARTILE",
|
|
4637
5191
|
"QUARTILE.EXC": "QUARTILE.EXKL",
|
|
4638
5192
|
"QUARTILE.INC": "QUARTILE.INKL",
|
|
@@ -5002,6 +5556,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
5002
5556
|
"FACTDOUBLE": "FACT.DOBLE",
|
|
5003
5557
|
"FALSE": "FALSO",
|
|
5004
5558
|
"FDIST": "DISTR.F",
|
|
5559
|
+
"FIELDVALUE": "VALORCAMPO",
|
|
5005
5560
|
"FILTER": "FILTRAR",
|
|
5006
5561
|
"FILTERXML": "XMLFILTRO",
|
|
5007
5562
|
"FIND": "ENCONTRAR",
|
|
@@ -5066,6 +5621,8 @@ const FORMULA_LOCALE_DATA = {
|
|
|
5066
5621
|
"IMLN": "IM.LN",
|
|
5067
5622
|
"IMLOG10": "IM.LOG10",
|
|
5068
5623
|
"IMLOG2": "IM.LOG2",
|
|
5624
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
5625
|
+
"IMPORTTEXT": "IMPORTTEXT",
|
|
5069
5626
|
"IMPOWER": "IM.POT",
|
|
5070
5627
|
"IMPRODUCT": "IM.PRODUCT",
|
|
5071
5628
|
"IMREAL": "IM.REAL",
|
|
@@ -5203,6 +5760,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
5203
5760
|
"PRODUCT": "PRODUCTO",
|
|
5204
5761
|
"PROPER": "NOMPROPIO",
|
|
5205
5762
|
"PV": "VA",
|
|
5763
|
+
"PY": "PY",
|
|
5206
5764
|
"QUARTILE": "CUARTIL",
|
|
5207
5765
|
"QUARTILE.EXC": "CUARTIL.EXC",
|
|
5208
5766
|
"QUARTILE.INC": "CUARTIL.INC",
|
|
@@ -5555,6 +6113,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
5555
6113
|
"FACTDOUBLE": "FACTDOUBLE",
|
|
5556
6114
|
"FALSE": "FAUX",
|
|
5557
6115
|
"FDIST": "LOI.F",
|
|
6116
|
+
"FIELDVALUE": "VALEURCHAMP",
|
|
5558
6117
|
"FILTER": "FILTRE",
|
|
5559
6118
|
"FILTERXML": "FILTRE.XML",
|
|
5560
6119
|
"FIND": "TROUVE",
|
|
@@ -5619,6 +6178,8 @@ const FORMULA_LOCALE_DATA = {
|
|
|
5619
6178
|
"IMLN": "COMPLEXE.LN",
|
|
5620
6179
|
"IMLOG10": "COMPLEXE.LOG10",
|
|
5621
6180
|
"IMLOG2": "COMPLEXE.LOG2",
|
|
6181
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
6182
|
+
"IMPORTTEXT": "IMPORTTEXT",
|
|
5622
6183
|
"IMPOWER": "COMPLEXE.PUISSANCE",
|
|
5623
6184
|
"IMPRODUCT": "COMPLEXE.PRODUIT",
|
|
5624
6185
|
"IMREAL": "COMPLEXE.REEL",
|
|
@@ -5754,6 +6315,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
5754
6315
|
"PRODUCT": "PRODUIT",
|
|
5755
6316
|
"PROPER": "NOMPROPRE",
|
|
5756
6317
|
"PV": "VA",
|
|
6318
|
+
"PY": "PY",
|
|
5757
6319
|
"QUARTILE": "QUARTILE",
|
|
5758
6320
|
"QUARTILE.EXC": "QUARTILE.EXCLURE",
|
|
5759
6321
|
"QUARTILE.INC": "QUARTILE.INCLURE",
|
|
@@ -6105,6 +6667,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
6105
6667
|
"FACTDOUBLE": "FATT.DOPPIO",
|
|
6106
6668
|
"FALSE": "FALSO",
|
|
6107
6669
|
"FDIST": "DISTRIB.F",
|
|
6670
|
+
"FIELDVALUE": "VALORECAMPO",
|
|
6108
6671
|
"FILTER": "FILTER",
|
|
6109
6672
|
"FILTERXML": "FILTRO.XML",
|
|
6110
6673
|
"FIND": "TROVA",
|
|
@@ -6169,6 +6732,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
6169
6732
|
"IMLN": "COMP.LN",
|
|
6170
6733
|
"IMLOG10": "COMP.LOG10",
|
|
6171
6734
|
"IMLOG2": "COMP.LOG2",
|
|
6735
|
+
"IMPORTTEXT": "IMPORTTEXT",
|
|
6172
6736
|
"IMPOWER": "COMP.POTENZA",
|
|
6173
6737
|
"IMPRODUCT": "COMP.PRODOTTO",
|
|
6174
6738
|
"IMREAL": "COMP.PARTE.REALE",
|
|
@@ -6306,6 +6870,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
6306
6870
|
"PRODUCT": "PRODOTTO",
|
|
6307
6871
|
"PROPER": "MAIUSC.INIZ",
|
|
6308
6872
|
"PV": "VA",
|
|
6873
|
+
"PY": "PY",
|
|
6309
6874
|
"QUARTILE": "QUARTILE",
|
|
6310
6875
|
"QUARTILE.EXC": "ESC.QUARTILE",
|
|
6311
6876
|
"QUARTILE.INC": "INC.QUARTILE",
|
|
@@ -6464,6 +7029,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
6464
7029
|
},
|
|
6465
7030
|
"uncertain": [
|
|
6466
7031
|
"FINDB",
|
|
7032
|
+
"IMPORTCSV",
|
|
6467
7033
|
"JIS",
|
|
6468
7034
|
"LEFTB",
|
|
6469
7035
|
"LENB",
|
|
@@ -6666,6 +7232,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
6666
7232
|
"FACTDOUBLE": "DUBBELE.FACULTEIT",
|
|
6667
7233
|
"FALSE": "ONWAAR",
|
|
6668
7234
|
"FDIST": "F.VERDELING",
|
|
7235
|
+
"FIELDVALUE": "VELDWAARDE",
|
|
6669
7236
|
"FILTER": "FILTER",
|
|
6670
7237
|
"FILTERXML": "XML.FILTEREN",
|
|
6671
7238
|
"FIND": "VIND.ALLES",
|
|
@@ -6730,6 +7297,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
6730
7297
|
"IMLN": "C.LN",
|
|
6731
7298
|
"IMLOG10": "C.LOG10",
|
|
6732
7299
|
"IMLOG2": "C.LOG2",
|
|
7300
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
6733
7301
|
"IMPOWER": "C.MACHT",
|
|
6734
7302
|
"IMPRODUCT": "C.PRODUCT",
|
|
6735
7303
|
"IMREAL": "C.REEEL.DEEL",
|
|
@@ -6867,6 +7435,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
6867
7435
|
"PRODUCT": "PRODUCT",
|
|
6868
7436
|
"PROPER": "BEGINLETTERS",
|
|
6869
7437
|
"PV": "HW",
|
|
7438
|
+
"PY": "PY",
|
|
6870
7439
|
"QUARTILE": "KWARTIEL",
|
|
6871
7440
|
"QUARTILE.EXC": "KWARTIEL.EXC",
|
|
6872
7441
|
"QUARTILE.INC": "KWARTIEL.INC",
|
|
@@ -7028,6 +7597,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
7028
7597
|
},
|
|
7029
7598
|
"uncertain": [
|
|
7030
7599
|
"FINDB",
|
|
7600
|
+
"IMPORTTEXT",
|
|
7031
7601
|
"JIS",
|
|
7032
7602
|
"LEFTB",
|
|
7033
7603
|
"LENB",
|
|
@@ -7220,6 +7790,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
7220
7790
|
"FACTDOUBLE": "SILNIA.DWUKR",
|
|
7221
7791
|
"FALSE": "FAŁSZ",
|
|
7222
7792
|
"FDIST": "ROZKŁAD.F",
|
|
7793
|
+
"FIELDVALUE": "POLE.WARTOŚĆ",
|
|
7223
7794
|
"FILTER": "FILTER",
|
|
7224
7795
|
"FILTERXML": "FILTERXML",
|
|
7225
7796
|
"FIND": "ZNAJDŹ",
|
|
@@ -7284,6 +7855,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
7284
7855
|
"IMLN": "LN.LICZBY.ZESP",
|
|
7285
7856
|
"IMLOG10": "LOG10.LICZBY.ZESP",
|
|
7286
7857
|
"IMLOG2": "LOG2.LICZBY.ZESP",
|
|
7858
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
7287
7859
|
"IMPOWER": "POTĘGA.LICZBY.ZESP",
|
|
7288
7860
|
"IMPRODUCT": "ILOCZYN.LICZB.ZESP",
|
|
7289
7861
|
"IMREAL": "CZ.RZECZ.LICZBY.ZESP",
|
|
@@ -7422,6 +7994,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
7422
7994
|
"PRODUCT": "ILOCZYN",
|
|
7423
7995
|
"PROPER": "Z.WIELKIEJ.LITERY",
|
|
7424
7996
|
"PV": "PV",
|
|
7997
|
+
"PY": "PY",
|
|
7425
7998
|
"QUARTILE": "KWARTYL",
|
|
7426
7999
|
"QUARTILE.EXC": "KWARTYL.PRZEDZ.OTW",
|
|
7427
8000
|
"QUARTILE.INC": "KWARTYL.PRZEDZ.ZAMK",
|
|
@@ -7583,6 +8156,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
7583
8156
|
},
|
|
7584
8157
|
"uncertain": [
|
|
7585
8158
|
"FINDB",
|
|
8159
|
+
"IMPORTTEXT",
|
|
7586
8160
|
"LEFTB",
|
|
7587
8161
|
"LENB",
|
|
7588
8162
|
"MIDB",
|
|
@@ -7774,6 +8348,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
7774
8348
|
"FACTDOUBLE": "FATDUPLO",
|
|
7775
8349
|
"FALSE": "FALSO",
|
|
7776
8350
|
"FDIST": "DISTF",
|
|
8351
|
+
"FIELDVALUE": "VALORDOCAMPO",
|
|
7777
8352
|
"FILTER": "FILTRAR",
|
|
7778
8353
|
"FILTERXML": "FILTRARXML",
|
|
7779
8354
|
"FIND": "LOCALIZAR",
|
|
@@ -7838,6 +8413,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
7838
8413
|
"IMLN": "IMLN",
|
|
7839
8414
|
"IMLOG10": "IMLOG10",
|
|
7840
8415
|
"IMLOG2": "IMLOG2",
|
|
8416
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
7841
8417
|
"IMPOWER": "IMPOT",
|
|
7842
8418
|
"IMPRODUCT": "IMPROD",
|
|
7843
8419
|
"IMREAL": "IMREAL",
|
|
@@ -7975,6 +8551,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
7975
8551
|
"PRODUCT": "PRODUTO",
|
|
7976
8552
|
"PROPER": "INICIAL.MAIÚSCULA",
|
|
7977
8553
|
"PV": "VA",
|
|
8554
|
+
"PY": "PY",
|
|
7978
8555
|
"QUARTILE": "QUARTIL",
|
|
7979
8556
|
"QUARTILE.EXC": "QUARTIL.EXC",
|
|
7980
8557
|
"QUARTILE.INC": "QUARTIL.INC",
|
|
@@ -8134,6 +8711,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
8134
8711
|
},
|
|
8135
8712
|
"uncertain": [
|
|
8136
8713
|
"FINDB",
|
|
8714
|
+
"IMPORTTEXT",
|
|
8137
8715
|
"JIS",
|
|
8138
8716
|
"LEFTB",
|
|
8139
8717
|
"LENB",
|
|
@@ -8326,6 +8904,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
8326
8904
|
"FACTDOUBLE": "FATDUPLO",
|
|
8327
8905
|
"FALSE": "FALSO",
|
|
8328
8906
|
"FDIST": "DISTF",
|
|
8907
|
+
"FIELDVALUE": "VALORCAMPO",
|
|
8329
8908
|
"FILTER": "FILTRO",
|
|
8330
8909
|
"FILTERXML": "FILTROXML",
|
|
8331
8910
|
"FIND": "PROCURAR",
|
|
@@ -8390,6 +8969,8 @@ const FORMULA_LOCALE_DATA = {
|
|
|
8390
8969
|
"IMLN": "IMLN",
|
|
8391
8970
|
"IMLOG10": "IMLOG10",
|
|
8392
8971
|
"IMLOG2": "IMLOG2",
|
|
8972
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
8973
|
+
"IMPORTTEXT": "IMPORTTEXT",
|
|
8393
8974
|
"IMPOWER": "IMPOT",
|
|
8394
8975
|
"IMPRODUCT": "IMPROD",
|
|
8395
8976
|
"IMREAL": "IMREAL",
|
|
@@ -8526,6 +9107,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
8526
9107
|
"PRODUCT": "MULT",
|
|
8527
9108
|
"PROPER": "PRI.MAIÚSCULA",
|
|
8528
9109
|
"PV": "VP",
|
|
9110
|
+
"PY": "PY",
|
|
8529
9111
|
"QUARTILE": "QUARTIL",
|
|
8530
9112
|
"QUARTILE.EXC": "QUARTIL.EXC",
|
|
8531
9113
|
"QUARTILE.INC": "QUARTIL.INC",
|
|
@@ -8868,6 +9450,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
8868
9450
|
"FACTDOUBLE": "ДВФАКТР",
|
|
8869
9451
|
"FALSE": "ЛОЖЬ",
|
|
8870
9452
|
"FDIST": "FРАСП",
|
|
9453
|
+
"FIELDVALUE": "ЗНАЧПОЛЯ",
|
|
8871
9454
|
"FILTER": "ФИЛЬТР",
|
|
8872
9455
|
"FILTERXML": "ФИЛЬТР.XML",
|
|
8873
9456
|
"FIND": "НАЙТИ",
|
|
@@ -8933,6 +9516,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
8933
9516
|
"IMLN": "МНИМ.LN",
|
|
8934
9517
|
"IMLOG10": "МНИМ.LOG10",
|
|
8935
9518
|
"IMLOG2": "МНИМ.LOG2",
|
|
9519
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
8936
9520
|
"IMPOWER": "МНИМ.СТЕПЕНЬ",
|
|
8937
9521
|
"IMPRODUCT": "МНИМ.ПРОИЗВЕД",
|
|
8938
9522
|
"IMREAL": "МНИМ.ВЕЩ",
|
|
@@ -9074,6 +9658,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
9074
9658
|
"PRODUCT": "ПРОИЗВЕД",
|
|
9075
9659
|
"PROPER": "ПРОПНАЧ",
|
|
9076
9660
|
"PV": "ПС",
|
|
9661
|
+
"PY": "PY",
|
|
9077
9662
|
"QUARTILE": "КВАРТИЛЬ",
|
|
9078
9663
|
"QUARTILE.EXC": "КВАРТИЛЬ.ИСКЛ",
|
|
9079
9664
|
"QUARTILE.INC": "КВАРТИЛЬ.ВКЛ",
|
|
@@ -9238,6 +9823,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
9238
9823
|
"#VALUE!": "#ЗНАЧ!"
|
|
9239
9824
|
},
|
|
9240
9825
|
"uncertain": [
|
|
9826
|
+
"IMPORTTEXT",
|
|
9241
9827
|
"SINGLE"
|
|
9242
9828
|
]
|
|
9243
9829
|
},
|
|
@@ -9423,6 +10009,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
9423
10009
|
"FACTDOUBLE": "ÇİFTFAKTÖR",
|
|
9424
10010
|
"FALSE": "YANLIŞ",
|
|
9425
10011
|
"FDIST": "FDAĞ",
|
|
10012
|
+
"FIELDVALUE": "FIELDVALUE",
|
|
9426
10013
|
"FILTER": "FİLTRE",
|
|
9427
10014
|
"FILTERXML": "XMLFİLTRELE",
|
|
9428
10015
|
"FIND": "BUL",
|
|
@@ -9487,6 +10074,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
9487
10074
|
"IMLN": "SANLN",
|
|
9488
10075
|
"IMLOG10": "SANLOG10",
|
|
9489
10076
|
"IMLOG2": "SANLOG2",
|
|
10077
|
+
"IMPORTCSV": "IMPORTCSV",
|
|
9490
10078
|
"IMPOWER": "SANKUVVET",
|
|
9491
10079
|
"IMPRODUCT": "SANÇARP",
|
|
9492
10080
|
"IMREAL": "SANGERÇEK",
|
|
@@ -9625,6 +10213,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
9625
10213
|
"PRODUCT": "ÇARPIM",
|
|
9626
10214
|
"PROPER": "YAZIM.DÜZENİ",
|
|
9627
10215
|
"PV": "BD",
|
|
10216
|
+
"PY": "PY",
|
|
9628
10217
|
"QUARTILE": "DÖRTTEBİRLİK",
|
|
9629
10218
|
"QUARTILE.EXC": "DÖRTTEBİRLİK.HRC",
|
|
9630
10219
|
"QUARTILE.INC": "DÖRTTEBİRLİK.DHL",
|
|
@@ -9785,6 +10374,7 @@ const FORMULA_LOCALE_DATA = {
|
|
|
9785
10374
|
},
|
|
9786
10375
|
"uncertain": [
|
|
9787
10376
|
"FINDB",
|
|
10377
|
+
"IMPORTTEXT",
|
|
9788
10378
|
"LEFTB",
|
|
9789
10379
|
"LENB",
|
|
9790
10380
|
"MIDB",
|
|
@@ -31550,6 +32140,19 @@ const unavailable = () => {
|
|
|
31550
32140
|
throw FormulaError.NA;
|
|
31551
32141
|
};
|
|
31552
32142
|
|
|
32143
|
+
// The file imports (IMPORTTEXT, IMPORTCSV) and Python in Excel (PY) need a capability this engine
|
|
32144
|
+
// blocks (local files, a Python runtime): Excel reports that as #BLOCKED!. Linked data type fields
|
|
32145
|
+
// (FIELDVALUE, and `_FV` — `A1.Price` as a workbook file stores it) have no linked data types to
|
|
32146
|
+
// read here: #FIELD!, as Excel answers for a field the value does not have. Same answers as the
|
|
32147
|
+
// rnc engine (formualizer `builtins/external.rs`), so these are never #NAME? on either engine
|
|
32148
|
+
// (demo-app-monorepo#49969 FX-15).
|
|
32149
|
+
const blocked = () => {
|
|
32150
|
+
throw FormulaError.BLOCKED;
|
|
32151
|
+
};
|
|
32152
|
+
const noField = () => {
|
|
32153
|
+
throw FormulaError.FIELD;
|
|
32154
|
+
};
|
|
32155
|
+
|
|
31553
32156
|
const ExternalFunctions = {
|
|
31554
32157
|
CUBEKPIMEMBER: unavailable,
|
|
31555
32158
|
CUBEMEMBER: unavailable,
|
|
@@ -31566,6 +32169,11 @@ const ExternalFunctions = {
|
|
|
31566
32169
|
TRANSLATE: unavailable,
|
|
31567
32170
|
DETECTLANGUAGE: unavailable,
|
|
31568
32171
|
QUERY: unavailable,
|
|
32172
|
+
IMPORTTEXT: blocked,
|
|
32173
|
+
IMPORTCSV: blocked,
|
|
32174
|
+
PY: blocked,
|
|
32175
|
+
FIELDVALUE: noField,
|
|
32176
|
+
_FV: noField,
|
|
31569
32177
|
};
|
|
31570
32178
|
|
|
31571
32179
|
var api$3 = {};
|