@odoo/o-spreadsheet 19.4.7 → 19.4.9

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.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 19.4.7
6
- * @date 2026-08-12T09:16:40.949Z
7
- * @hash 65642fe
5
+ * @version 19.4.9
6
+ * @date 2026-08-21T15:33:39.385Z
7
+ * @hash b48dbb3
8
8
  */
9
9
 
10
10
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
@@ -4026,6 +4026,18 @@ function toString(data) {
4026
4026
  default: return "";
4027
4027
  }
4028
4028
  }
4029
+ /**
4030
+ * Only converts the decimal separator, ignore number format such as % or dates
4031
+ */
4032
+ function toLocaleString(data, locale) {
4033
+ const value = toValue(data);
4034
+ switch (typeof value) {
4035
+ case "string": return value;
4036
+ case "number": return value.toString().replace(".", locale.decimalSeparator);
4037
+ case "boolean": return value ? "TRUE" : "FALSE";
4038
+ default: return "";
4039
+ }
4040
+ }
4029
4041
  /** Normalize string by setting it to lowercase and replacing accent letters with plain letters */
4030
4042
  const normalizeString = memoize(function normalizeString(str) {
4031
4043
  return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
@@ -15479,18 +15491,21 @@ const figureRegistry = new Registry();
15479
15491
  figureRegistry.add("chart", {
15480
15492
  Component: ChartFigure,
15481
15493
  SidePanelComponent: "ChartPanel",
15482
- menuBuilder: getChartMenuActions
15494
+ menuBuilder: getChartMenuActions,
15495
+ isThemeDependant: true
15483
15496
  });
15484
15497
  figureRegistry.add("image", {
15485
15498
  Component: ImageFigure,
15486
15499
  keepRatio: true,
15487
15500
  minFigSize: 20,
15488
15501
  borderWidth: 0,
15489
- menuBuilder: getImageMenuActions
15502
+ menuBuilder: getImageMenuActions,
15503
+ isThemeDependant: false
15490
15504
  });
15491
15505
  figureRegistry.add("carousel", {
15492
15506
  Component: CarouselFigure,
15493
- menuBuilder: getCarouselMenuActions
15507
+ menuBuilder: getCarouselMenuActions,
15508
+ isThemeDependant: true
15494
15509
  });
15495
15510
 
15496
15511
  //#endregion
@@ -15519,6 +15534,9 @@ var FigureComponent = class extends Component {
15519
15534
  get isSelected() {
15520
15535
  return this.env.model.getters.getSelectedFigureIds().includes(this.props.figureUI.id);
15521
15536
  }
15537
+ get isThemeDependant() {
15538
+ return figureRegistry.get(this.props.figureUI.tag).isThemeDependant;
15539
+ }
15522
15540
  get figureRegistry() {
15523
15541
  return figureRegistry;
15524
15542
  }
@@ -78026,12 +78044,13 @@ var FilterMenu = class extends Component {
78026
78044
  }
78027
78045
  sortFilterZone(sortDirection) {
78028
78046
  const filterPosition = this.props.filterPosition;
78029
- const tableZone = this.table?.range.zone;
78047
+ const table = this.table;
78048
+ const tableZone = table?.range.zone;
78030
78049
  if (!filterPosition || !tableZone || tableZone.top === tableZone.bottom) return;
78031
78050
  const sheetId = this.env.model.getters.getActiveSheetId();
78032
78051
  const contentZone = {
78033
78052
  ...tableZone,
78034
- top: tableZone.top + 1
78053
+ top: tableZone.top + table.config.numberOfHeaders
78035
78054
  };
78036
78055
  const sortAnchor = {
78037
78056
  col: filterPosition.col,
@@ -80288,7 +80307,7 @@ const ARRAYTOTEXT = {
80288
80307
  else if (_format === 0) {
80289
80308
  const rowSeparator = this.locale.decimalSeparator === "," ? "/" : ",";
80290
80309
  return transposeMatrix(_array).flatMap((row) => row.map((value) => {
80291
- return isEvaluationError(value.value) ? value.value : toString(value);
80310
+ return isEvaluationError(value.value) ? value.value : toLocaleString(value, this.locale);
80292
80311
  })).join(rowSeparator);
80293
80312
  } else return new EvaluationError(_t("Format must be 0 or 1"));
80294
80313
  },
@@ -86054,7 +86073,7 @@ const CONCAT = {
86054
86073
  description: _t("Concatenation of two values."),
86055
86074
  args: [arg("value1 (string)", _t("The value to which value2 will be appended.")), arg("value2 (string)", _t("The value to append to value1."))],
86056
86075
  compute: function(value1, value2) {
86057
- return toString(value1) + toString(value2);
86076
+ return toLocaleString(value1, this.locale) + toLocaleString(value2, this.locale);
86058
86077
  },
86059
86078
  isExported: true
86060
86079
  };
@@ -86937,7 +86956,7 @@ const CLEAN = {
86937
86956
  description: _t("Remove non-printable characters from a piece of text."),
86938
86957
  args: [arg("text (string)", _t("The text whose non-printable characters are to be removed."))],
86939
86958
  compute: function(text) {
86940
- const _text = toString(text);
86959
+ const _text = toLocaleString(text, this.locale);
86941
86960
  let cleanedStr = "";
86942
86961
  for (const char of _text) if (char && char.charCodeAt(0) > 31) cleanedStr += char;
86943
86962
  return cleanedStr;
@@ -86948,7 +86967,7 @@ const CONCATENATE = {
86948
86967
  description: _t("Appends strings to one another."),
86949
86968
  args: [arg("string (string, range<string>, repeating)", _t("String to append in sequence."))],
86950
86969
  compute: function(...datas) {
86951
- return reduceAny(datas, (acc, a) => acc + toString(a), "");
86970
+ return reduceAny(datas, (acc, a) => acc + toLocaleString(a, this.locale), "");
86952
86971
  },
86953
86972
  isExported: true
86954
86973
  };
@@ -86956,7 +86975,7 @@ const EXACT = {
86956
86975
  description: _t("Tests whether two strings are identical."),
86957
86976
  args: [arg("string1 (string)", _t("The first string to compare.")), arg("string2 (string)", _t("The second string to compare."))],
86958
86977
  compute: function(string1, string2) {
86959
- return toString(string1) === toString(string2);
86978
+ return toLocaleString(string1, this.locale) === toLocaleString(string2, this.locale);
86960
86979
  },
86961
86980
  isExported: true
86962
86981
  };
@@ -86968,8 +86987,8 @@ const FIND = {
86968
86987
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search."))
86969
86988
  ],
86970
86989
  compute: function(searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
86971
- const _searchFor = toString(searchFor);
86972
- const _textToSearch = toString(textToSearch);
86990
+ const _searchFor = toLocaleString(searchFor, this.locale);
86991
+ const _textToSearch = toLocaleString(textToSearch, this.locale);
86973
86992
  const _startingAt = toNumber(startingAt, this.locale);
86974
86993
  if (_textToSearch === "") return new EvaluationError(_t("The text_to_search must be non-empty."));
86975
86994
  if (_startingAt < 1) return new EvaluationError(_t("The starting_at (%s) must be greater than or equal to 1.", _startingAt));
@@ -87006,8 +87025,8 @@ const JOIN = {
87006
87025
  description: _t("Concatenates elements of arrays with delimiter."),
87007
87026
  args: [arg("delimiter (string)", _t("The character or string to place between each concatenated value.")), arg("value_or_array (string, range<string>, repeating)", _t("Value to be appended using delimiter."))],
87008
87027
  compute: function(delimiter, ...valuesOrArrays) {
87009
- const _delimiter = toString(delimiter);
87010
- return reduceAny(valuesOrArrays, (acc, a) => (acc ? acc + _delimiter : "") + toString(a), "");
87028
+ const _delimiter = toLocaleString(delimiter, this.locale);
87029
+ return reduceAny(valuesOrArrays, (acc, a) => (acc ? acc + _delimiter : "") + toLocaleString(a, this.locale), "");
87011
87030
  }
87012
87031
  };
87013
87032
  const LEFT = {
@@ -87016,7 +87035,7 @@ const LEFT = {
87016
87035
  compute: function(text, ...args) {
87017
87036
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
87018
87037
  if (_numberOfCharacters < 0) return new EvaluationError(_t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters));
87019
- return toString(text).substring(0, _numberOfCharacters);
87038
+ return toLocaleString(text, this.locale).substring(0, _numberOfCharacters);
87020
87039
  },
87021
87040
  isExported: true
87022
87041
  };
@@ -87024,7 +87043,7 @@ const LEN = {
87024
87043
  description: _t("Length of a string."),
87025
87044
  args: [arg("text (string)", _t("The string whose length will be returned."))],
87026
87045
  compute: function(text) {
87027
- return toString(text).length;
87046
+ return toLocaleString(text, this.locale).length;
87028
87047
  },
87029
87048
  isExported: true
87030
87049
  };
@@ -87032,7 +87051,7 @@ const LOWER = {
87032
87051
  description: _t("Converts a specified string to lowercase."),
87033
87052
  args: [arg("text (string)", _t("The string to convert to lowercase."))],
87034
87053
  compute: function(text) {
87035
- return toString(text).toLowerCase();
87054
+ return toLocaleString(text, this.locale).toLowerCase();
87036
87055
  },
87037
87056
  isExported: true
87038
87057
  };
@@ -87044,7 +87063,7 @@ const MID = {
87044
87063
  arg("extract_length (number)", _t("The length of the segment to extract."))
87045
87064
  ],
87046
87065
  compute: function(text, starting_at, extract_length) {
87047
- const _text = toString(text);
87066
+ const _text = toLocaleString(text, this.locale);
87048
87067
  const _starting_at = toNumber(starting_at, this.locale);
87049
87068
  const _extract_length = toNumber(extract_length, this.locale);
87050
87069
  if (_starting_at < 1) return new EvaluationError(_t("The starting_at argument (%s) must be positive greater than one.", _starting_at.toString()));
@@ -87057,7 +87076,7 @@ const PROPER = {
87057
87076
  description: _t("Capitalizes each word in a specified string."),
87058
87077
  args: [arg("text_to_capitalize (string)", _t("The text which will be returned with the first letter of each word in uppercase and all other letters in lowercase."))],
87059
87078
  compute: function(text) {
87060
- return toString(text).replace(wordRegex, (word) => {
87079
+ return toLocaleString(text, this.locale).replace(wordRegex, (word) => {
87061
87080
  return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
87062
87081
  });
87063
87082
  },
@@ -87207,8 +87226,8 @@ const REPLACE = {
87207
87226
  if (_position < 1) return new EvaluationError(_t("The position (%s) must be greater than or equal to 1.", _position));
87208
87227
  const _length = toNumber(length, this.locale);
87209
87228
  if (_length < 0) return new EvaluationError(_t("The length (%s) must be positive or zero.", _length));
87210
- const _text = toString(text);
87211
- const _newText = toString(newText);
87229
+ const _text = toLocaleString(text, this.locale);
87230
+ const _newText = toLocaleString(newText, this.locale);
87212
87231
  return _text.substring(0, _position - 1) + _newText + _text.substring(_position - 1 + _length);
87213
87232
  },
87214
87233
  isExported: true
@@ -87219,7 +87238,7 @@ const RIGHT = {
87219
87238
  compute: function(text, ...args) {
87220
87239
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
87221
87240
  if (_numberOfCharacters < 0) return new EvaluationError(_t("The number_of_characters (%s) must be positive or zero.", _numberOfCharacters));
87222
- const _text = toString(text);
87241
+ const _text = toLocaleString(text, this.locale);
87223
87242
  const stringLength = _text.length;
87224
87243
  return _text.substring(stringLength - _numberOfCharacters, stringLength);
87225
87244
  },
@@ -87233,8 +87252,8 @@ const SEARCH = {
87233
87252
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search."))
87234
87253
  ],
87235
87254
  compute: function(searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
87236
- const _searchFor = toString(searchFor).toLowerCase();
87237
- const _textToSearch = toString(textToSearch).toLowerCase();
87255
+ const _searchFor = toLocaleString(searchFor, this.locale).toLowerCase();
87256
+ const _textToSearch = toLocaleString(textToSearch, this.locale).toLowerCase();
87238
87257
  const _startingAt = toNumber(startingAt, this.locale);
87239
87258
  if (_textToSearch === "") return {
87240
87259
  value: CellErrorType.GenericError,
@@ -87264,8 +87283,8 @@ const SPLIT = {
87264
87283
  arg(`remove_empty_text (boolean, default=${SPLIT_DEFAULT_REMOVE_EMPTY_TEXT})`, _t("Whether or not to remove empty text messages from the split results. The default behavior is to treat consecutive delimiters as one (if TRUE). If FALSE, empty cells values are added between consecutive delimiters."))
87265
87284
  ],
87266
87285
  compute: function(text, delimiter, splitByEach = { value: SPLIT_DEFAULT_SPLIT_BY_EACH }, removeEmptyText = { value: SPLIT_DEFAULT_REMOVE_EMPTY_TEXT }) {
87267
- const _text = toString(text);
87268
- const _delimiter = escapeRegExp(toString(delimiter));
87286
+ const _text = toLocaleString(text, this.locale);
87287
+ const _delimiter = escapeRegExp(toLocaleString(delimiter, this.locale));
87269
87288
  const _splitByEach = toBoolean(splitByEach);
87270
87289
  const _removeEmptyText = toBoolean(removeEmptyText);
87271
87290
  if (_delimiter.length <= 0) return new EvaluationError(_t("The delimiter (%s) must be not be empty.", _delimiter));
@@ -87287,10 +87306,10 @@ const SUBSTITUTE = {
87287
87306
  compute: function(textToSearch, searchFor, replaceWith, occurrenceNumber) {
87288
87307
  const _occurrenceNumber = toNumber(occurrenceNumber, this.locale);
87289
87308
  if (_occurrenceNumber < 0) return new EvaluationError(_t("The occurrenceNumber (%s) must be positive or null.", _occurrenceNumber));
87290
- const _textToSearch = toString(textToSearch);
87291
- const _searchFor = toString(searchFor);
87309
+ const _textToSearch = toLocaleString(textToSearch, this.locale);
87310
+ const _searchFor = toLocaleString(searchFor, this.locale);
87292
87311
  if (_searchFor === "") return _textToSearch;
87293
- const _replaceWith = toString(replaceWith);
87312
+ const _replaceWith = toLocaleString(replaceWith, this.locale);
87294
87313
  const reg = new RegExp(escapeRegExp(_searchFor), "g");
87295
87314
  if (_occurrenceNumber === 0) return _textToSearch.replace(reg, _replaceWith);
87296
87315
  let n = 0;
@@ -87313,10 +87332,10 @@ const TEXTJOIN = {
87313
87332
  arg("texts (string, range<string>, repeating)", _t("Text item to join."))
87314
87333
  ],
87315
87334
  compute: function(delimiter, ignoreEmpty = { value: TEXTJOIN_DEFAULT_IGNORE_EMPTY }, ...textsOrArrays) {
87316
- const _delimiter = toString(delimiter);
87335
+ const _delimiter = toLocaleString(delimiter, this.locale);
87317
87336
  const _ignoreEmpty = toBoolean(ignoreEmpty);
87318
87337
  let n = 0;
87319
- return reduceAny(textsOrArrays, (acc, a) => !(_ignoreEmpty && toString(a) === "") ? (n++ ? acc + _delimiter : "") + toString(a) : acc, "");
87338
+ return reduceAny(textsOrArrays, (acc, a) => !(_ignoreEmpty && toLocaleString(a, this.locale) === "") ? (n++ ? acc + _delimiter : "") + toLocaleString(a, this.locale) : acc, "");
87320
87339
  },
87321
87340
  isExported: true
87322
87341
  };
@@ -87369,7 +87388,7 @@ const TRIM = {
87369
87388
  description: _t("Removes space characters."),
87370
87389
  args: [arg("text (string)", _t("The text or reference to a cell containing text to be trimmed."))],
87371
87390
  compute: function(text) {
87372
- return trimContent(toString(text));
87391
+ return trimContent(toLocaleString(text, this.locale));
87373
87392
  },
87374
87393
  isExported: true
87375
87394
  };
@@ -87377,7 +87396,7 @@ const UPPER = {
87377
87396
  description: _t("Converts a specified string to uppercase."),
87378
87397
  args: [arg("text (string)", _t("The string to convert to uppercase."))],
87379
87398
  compute: function(text) {
87380
- return toString(text).toUpperCase();
87399
+ return toLocaleString(text, this.locale).toUpperCase();
87381
87400
  },
87382
87401
  isExported: true
87383
87402
  };
@@ -87474,7 +87493,7 @@ const HYPERLINK = {
87474
87493
  args: [arg("url (string)", _t("The full URL of the link enclosed in quotation marks.")), arg("link_label (string, optional)", _t("The text to display in the cell, enclosed in quotation marks."))],
87475
87494
  compute: function(url, linkLabel) {
87476
87495
  const processedUrl = toString(url).trim();
87477
- const processedLabel = toString(linkLabel) || processedUrl;
87496
+ const processedLabel = toLocaleString(linkLabel, this.locale) || processedUrl;
87478
87497
  if (processedUrl === "") return processedLabel;
87479
87498
  return markdownLink(processedLabel, processedUrl);
87480
87499
  },
@@ -87923,6 +87942,6 @@ exports.stores = stores;
87923
87942
  exports.tokenColors = tokenColors;
87924
87943
  exports.tokenize = tokenize;
87925
87944
 
87926
- __info__.version = "19.4.7";
87927
- __info__.date = "2026-08-12T09:16:40.949Z";
87928
- __info__.hash = "65642fe";
87945
+ __info__.version = "19.4.9";
87946
+ __info__.date = "2026-08-21T15:33:39.385Z";
87947
+ __info__.hash = "b48dbb3";
@@ -2,9 +2,9 @@
2
2
  /*
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 19.4.7
6
- * @date 2026-08-12T09:16:42.630Z
7
- * @hash 65642fe
5
+ * @version 19.4.9
6
+ * @date 2026-08-21T15:33:40.993Z
7
+ * @hash b48dbb3
8
8
  */
9
9
  :root {
10
10
  --os-gray-100: light-dark(#f9fafb, #1b1d26);
@@ -311,6 +311,7 @@
311
311
  .os-input {
312
312
  border-width: 0 0 1px 0;
313
313
  border-color: transparent;
314
+ border-style: solid;
314
315
  outline: none;
315
316
  text-overflow: ellipsis;
316
317
  color: var(--os-text-body);
@@ -642,6 +643,7 @@
642
643
  width: 100%;
643
644
  outline: none;
644
645
  border-color: var(--os-border-color);
646
+ border-style: solid;
645
647
  color: var(--os-gray-900);
646
648
 
647
649
  &::placeholder {
@@ -2565,6 +2567,22 @@
2565
2567
  }
2566
2568
  }
2567
2569
 
2570
+ /* Originates from src/components/figures/figure_image/figure_image.css */
2571
+ .o-spreadsheet {
2572
+ .o-figure-menu-item {
2573
+ cursor: pointer;
2574
+ color: var(--os-gray-900) !important;
2575
+ height: 20px;
2576
+ width: 20px;
2577
+ &.active,
2578
+ &:hover,
2579
+ &:target {
2580
+ cursor: pointer;
2581
+ background-color: var(--os-background-gray-color-hover);
2582
+ }
2583
+ }
2584
+ }
2585
+
2568
2586
  /* Originates from src/components/figures/figure_container/figure_container.css */
2569
2587
  .o-spreadsheet {
2570
2588
  .o-figure-snap-line {
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 19.4.7
6
- * @date 2026-08-12T09:16:40.949Z
7
- * @hash 65642fe
5
+ * @version 19.4.9
6
+ * @date 2026-08-21T15:33:39.385Z
7
+ * @hash b48dbb3
8
8
  */
9
9
 
10
10
  import * as owl from "@odoo/owl";
@@ -4025,6 +4025,18 @@ function toString(data) {
4025
4025
  default: return "";
4026
4026
  }
4027
4027
  }
4028
+ /**
4029
+ * Only converts the decimal separator, ignore number format such as % or dates
4030
+ */
4031
+ function toLocaleString(data, locale) {
4032
+ const value = toValue(data);
4033
+ switch (typeof value) {
4034
+ case "string": return value;
4035
+ case "number": return value.toString().replace(".", locale.decimalSeparator);
4036
+ case "boolean": return value ? "TRUE" : "FALSE";
4037
+ default: return "";
4038
+ }
4039
+ }
4028
4040
  /** Normalize string by setting it to lowercase and replacing accent letters with plain letters */
4029
4041
  const normalizeString = memoize(function normalizeString(str) {
4030
4042
  return str.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
@@ -15478,18 +15490,21 @@ const figureRegistry = new Registry();
15478
15490
  figureRegistry.add("chart", {
15479
15491
  Component: ChartFigure,
15480
15492
  SidePanelComponent: "ChartPanel",
15481
- menuBuilder: getChartMenuActions
15493
+ menuBuilder: getChartMenuActions,
15494
+ isThemeDependant: true
15482
15495
  });
15483
15496
  figureRegistry.add("image", {
15484
15497
  Component: ImageFigure,
15485
15498
  keepRatio: true,
15486
15499
  minFigSize: 20,
15487
15500
  borderWidth: 0,
15488
- menuBuilder: getImageMenuActions
15501
+ menuBuilder: getImageMenuActions,
15502
+ isThemeDependant: false
15489
15503
  });
15490
15504
  figureRegistry.add("carousel", {
15491
15505
  Component: CarouselFigure,
15492
- menuBuilder: getCarouselMenuActions
15506
+ menuBuilder: getCarouselMenuActions,
15507
+ isThemeDependant: true
15493
15508
  });
15494
15509
 
15495
15510
  //#endregion
@@ -15518,6 +15533,9 @@ var FigureComponent = class extends Component {
15518
15533
  get isSelected() {
15519
15534
  return this.env.model.getters.getSelectedFigureIds().includes(this.props.figureUI.id);
15520
15535
  }
15536
+ get isThemeDependant() {
15537
+ return figureRegistry.get(this.props.figureUI.tag).isThemeDependant;
15538
+ }
15521
15539
  get figureRegistry() {
15522
15540
  return figureRegistry;
15523
15541
  }
@@ -77841,12 +77859,13 @@ var FilterMenu = class extends Component {
77841
77859
  }
77842
77860
  sortFilterZone(sortDirection) {
77843
77861
  const filterPosition = this.props.filterPosition;
77844
- const tableZone = this.table?.range.zone;
77862
+ const table = this.table;
77863
+ const tableZone = table?.range.zone;
77845
77864
  if (!filterPosition || !tableZone || tableZone.top === tableZone.bottom) return;
77846
77865
  const sheetId = this.env.model.getters.getActiveSheetId();
77847
77866
  const contentZone = {
77848
77867
  ...tableZone,
77849
- top: tableZone.top + 1
77868
+ top: tableZone.top + table.config.numberOfHeaders
77850
77869
  };
77851
77870
  const sortAnchor = {
77852
77871
  col: filterPosition.col,
@@ -80103,7 +80122,7 @@ const ARRAYTOTEXT = {
80103
80122
  else if (_format === 0) {
80104
80123
  const rowSeparator = this.locale.decimalSeparator === "," ? "/" : ",";
80105
80124
  return transposeMatrix(_array).flatMap((row) => row.map((value) => {
80106
- return isEvaluationError(value.value) ? value.value : toString(value);
80125
+ return isEvaluationError(value.value) ? value.value : toLocaleString(value, this.locale);
80107
80126
  })).join(rowSeparator);
80108
80127
  } else return new EvaluationError(_t("Format must be 0 or 1"));
80109
80128
  },
@@ -85869,7 +85888,7 @@ const CONCAT = {
85869
85888
  description: _t("Concatenation of two values."),
85870
85889
  args: [arg("value1 (string)", _t("The value to which value2 will be appended.")), arg("value2 (string)", _t("The value to append to value1."))],
85871
85890
  compute: function(value1, value2) {
85872
- return toString(value1) + toString(value2);
85891
+ return toLocaleString(value1, this.locale) + toLocaleString(value2, this.locale);
85873
85892
  },
85874
85893
  isExported: true
85875
85894
  };
@@ -86752,7 +86771,7 @@ const CLEAN = {
86752
86771
  description: _t("Remove non-printable characters from a piece of text."),
86753
86772
  args: [arg("text (string)", _t("The text whose non-printable characters are to be removed."))],
86754
86773
  compute: function(text) {
86755
- const _text = toString(text);
86774
+ const _text = toLocaleString(text, this.locale);
86756
86775
  let cleanedStr = "";
86757
86776
  for (const char of _text) if (char && char.charCodeAt(0) > 31) cleanedStr += char;
86758
86777
  return cleanedStr;
@@ -86763,7 +86782,7 @@ const CONCATENATE = {
86763
86782
  description: _t("Appends strings to one another."),
86764
86783
  args: [arg("string (string, range<string>, repeating)", _t("String to append in sequence."))],
86765
86784
  compute: function(...datas) {
86766
- return reduceAny(datas, (acc, a) => acc + toString(a), "");
86785
+ return reduceAny(datas, (acc, a) => acc + toLocaleString(a, this.locale), "");
86767
86786
  },
86768
86787
  isExported: true
86769
86788
  };
@@ -86771,7 +86790,7 @@ const EXACT = {
86771
86790
  description: _t("Tests whether two strings are identical."),
86772
86791
  args: [arg("string1 (string)", _t("The first string to compare.")), arg("string2 (string)", _t("The second string to compare."))],
86773
86792
  compute: function(string1, string2) {
86774
- return toString(string1) === toString(string2);
86793
+ return toLocaleString(string1, this.locale) === toLocaleString(string2, this.locale);
86775
86794
  },
86776
86795
  isExported: true
86777
86796
  };
@@ -86783,8 +86802,8 @@ const FIND = {
86783
86802
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search."))
86784
86803
  ],
86785
86804
  compute: function(searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
86786
- const _searchFor = toString(searchFor);
86787
- const _textToSearch = toString(textToSearch);
86805
+ const _searchFor = toLocaleString(searchFor, this.locale);
86806
+ const _textToSearch = toLocaleString(textToSearch, this.locale);
86788
86807
  const _startingAt = toNumber(startingAt, this.locale);
86789
86808
  if (_textToSearch === "") return new EvaluationError(_t("The text_to_search must be non-empty."));
86790
86809
  if (_startingAt < 1) return new EvaluationError(_t("The starting_at (%s) must be greater than or equal to 1.", _startingAt));
@@ -86821,8 +86840,8 @@ const JOIN = {
86821
86840
  description: _t("Concatenates elements of arrays with delimiter."),
86822
86841
  args: [arg("delimiter (string)", _t("The character or string to place between each concatenated value.")), arg("value_or_array (string, range<string>, repeating)", _t("Value to be appended using delimiter."))],
86823
86842
  compute: function(delimiter, ...valuesOrArrays) {
86824
- const _delimiter = toString(delimiter);
86825
- return reduceAny(valuesOrArrays, (acc, a) => (acc ? acc + _delimiter : "") + toString(a), "");
86843
+ const _delimiter = toLocaleString(delimiter, this.locale);
86844
+ return reduceAny(valuesOrArrays, (acc, a) => (acc ? acc + _delimiter : "") + toLocaleString(a, this.locale), "");
86826
86845
  }
86827
86846
  };
86828
86847
  const LEFT = {
@@ -86831,7 +86850,7 @@ const LEFT = {
86831
86850
  compute: function(text, ...args) {
86832
86851
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
86833
86852
  if (_numberOfCharacters < 0) return new EvaluationError(_t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters));
86834
- return toString(text).substring(0, _numberOfCharacters);
86853
+ return toLocaleString(text, this.locale).substring(0, _numberOfCharacters);
86835
86854
  },
86836
86855
  isExported: true
86837
86856
  };
@@ -86839,7 +86858,7 @@ const LEN = {
86839
86858
  description: _t("Length of a string."),
86840
86859
  args: [arg("text (string)", _t("The string whose length will be returned."))],
86841
86860
  compute: function(text) {
86842
- return toString(text).length;
86861
+ return toLocaleString(text, this.locale).length;
86843
86862
  },
86844
86863
  isExported: true
86845
86864
  };
@@ -86847,7 +86866,7 @@ const LOWER = {
86847
86866
  description: _t("Converts a specified string to lowercase."),
86848
86867
  args: [arg("text (string)", _t("The string to convert to lowercase."))],
86849
86868
  compute: function(text) {
86850
- return toString(text).toLowerCase();
86869
+ return toLocaleString(text, this.locale).toLowerCase();
86851
86870
  },
86852
86871
  isExported: true
86853
86872
  };
@@ -86859,7 +86878,7 @@ const MID = {
86859
86878
  arg("extract_length (number)", _t("The length of the segment to extract."))
86860
86879
  ],
86861
86880
  compute: function(text, starting_at, extract_length) {
86862
- const _text = toString(text);
86881
+ const _text = toLocaleString(text, this.locale);
86863
86882
  const _starting_at = toNumber(starting_at, this.locale);
86864
86883
  const _extract_length = toNumber(extract_length, this.locale);
86865
86884
  if (_starting_at < 1) return new EvaluationError(_t("The starting_at argument (%s) must be positive greater than one.", _starting_at.toString()));
@@ -86872,7 +86891,7 @@ const PROPER = {
86872
86891
  description: _t("Capitalizes each word in a specified string."),
86873
86892
  args: [arg("text_to_capitalize (string)", _t("The text which will be returned with the first letter of each word in uppercase and all other letters in lowercase."))],
86874
86893
  compute: function(text) {
86875
- return toString(text).replace(wordRegex, (word) => {
86894
+ return toLocaleString(text, this.locale).replace(wordRegex, (word) => {
86876
86895
  return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
86877
86896
  });
86878
86897
  },
@@ -87022,8 +87041,8 @@ const REPLACE = {
87022
87041
  if (_position < 1) return new EvaluationError(_t("The position (%s) must be greater than or equal to 1.", _position));
87023
87042
  const _length = toNumber(length, this.locale);
87024
87043
  if (_length < 0) return new EvaluationError(_t("The length (%s) must be positive or zero.", _length));
87025
- const _text = toString(text);
87026
- const _newText = toString(newText);
87044
+ const _text = toLocaleString(text, this.locale);
87045
+ const _newText = toLocaleString(newText, this.locale);
87027
87046
  return _text.substring(0, _position - 1) + _newText + _text.substring(_position - 1 + _length);
87028
87047
  },
87029
87048
  isExported: true
@@ -87034,7 +87053,7 @@ const RIGHT = {
87034
87053
  compute: function(text, ...args) {
87035
87054
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
87036
87055
  if (_numberOfCharacters < 0) return new EvaluationError(_t("The number_of_characters (%s) must be positive or zero.", _numberOfCharacters));
87037
- const _text = toString(text);
87056
+ const _text = toLocaleString(text, this.locale);
87038
87057
  const stringLength = _text.length;
87039
87058
  return _text.substring(stringLength - _numberOfCharacters, stringLength);
87040
87059
  },
@@ -87048,8 +87067,8 @@ const SEARCH = {
87048
87067
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search."))
87049
87068
  ],
87050
87069
  compute: function(searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
87051
- const _searchFor = toString(searchFor).toLowerCase();
87052
- const _textToSearch = toString(textToSearch).toLowerCase();
87070
+ const _searchFor = toLocaleString(searchFor, this.locale).toLowerCase();
87071
+ const _textToSearch = toLocaleString(textToSearch, this.locale).toLowerCase();
87053
87072
  const _startingAt = toNumber(startingAt, this.locale);
87054
87073
  if (_textToSearch === "") return {
87055
87074
  value: CellErrorType.GenericError,
@@ -87079,8 +87098,8 @@ const SPLIT = {
87079
87098
  arg(`remove_empty_text (boolean, default=${SPLIT_DEFAULT_REMOVE_EMPTY_TEXT})`, _t("Whether or not to remove empty text messages from the split results. The default behavior is to treat consecutive delimiters as one (if TRUE). If FALSE, empty cells values are added between consecutive delimiters."))
87080
87099
  ],
87081
87100
  compute: function(text, delimiter, splitByEach = { value: SPLIT_DEFAULT_SPLIT_BY_EACH }, removeEmptyText = { value: SPLIT_DEFAULT_REMOVE_EMPTY_TEXT }) {
87082
- const _text = toString(text);
87083
- const _delimiter = escapeRegExp(toString(delimiter));
87101
+ const _text = toLocaleString(text, this.locale);
87102
+ const _delimiter = escapeRegExp(toLocaleString(delimiter, this.locale));
87084
87103
  const _splitByEach = toBoolean(splitByEach);
87085
87104
  const _removeEmptyText = toBoolean(removeEmptyText);
87086
87105
  if (_delimiter.length <= 0) return new EvaluationError(_t("The delimiter (%s) must be not be empty.", _delimiter));
@@ -87102,10 +87121,10 @@ const SUBSTITUTE = {
87102
87121
  compute: function(textToSearch, searchFor, replaceWith, occurrenceNumber) {
87103
87122
  const _occurrenceNumber = toNumber(occurrenceNumber, this.locale);
87104
87123
  if (_occurrenceNumber < 0) return new EvaluationError(_t("The occurrenceNumber (%s) must be positive or null.", _occurrenceNumber));
87105
- const _textToSearch = toString(textToSearch);
87106
- const _searchFor = toString(searchFor);
87124
+ const _textToSearch = toLocaleString(textToSearch, this.locale);
87125
+ const _searchFor = toLocaleString(searchFor, this.locale);
87107
87126
  if (_searchFor === "") return _textToSearch;
87108
- const _replaceWith = toString(replaceWith);
87127
+ const _replaceWith = toLocaleString(replaceWith, this.locale);
87109
87128
  const reg = new RegExp(escapeRegExp(_searchFor), "g");
87110
87129
  if (_occurrenceNumber === 0) return _textToSearch.replace(reg, _replaceWith);
87111
87130
  let n = 0;
@@ -87128,10 +87147,10 @@ const TEXTJOIN = {
87128
87147
  arg("texts (string, range<string>, repeating)", _t("Text item to join."))
87129
87148
  ],
87130
87149
  compute: function(delimiter, ignoreEmpty = { value: TEXTJOIN_DEFAULT_IGNORE_EMPTY }, ...textsOrArrays) {
87131
- const _delimiter = toString(delimiter);
87150
+ const _delimiter = toLocaleString(delimiter, this.locale);
87132
87151
  const _ignoreEmpty = toBoolean(ignoreEmpty);
87133
87152
  let n = 0;
87134
- return reduceAny(textsOrArrays, (acc, a) => !(_ignoreEmpty && toString(a) === "") ? (n++ ? acc + _delimiter : "") + toString(a) : acc, "");
87153
+ return reduceAny(textsOrArrays, (acc, a) => !(_ignoreEmpty && toLocaleString(a, this.locale) === "") ? (n++ ? acc + _delimiter : "") + toLocaleString(a, this.locale) : acc, "");
87135
87154
  },
87136
87155
  isExported: true
87137
87156
  };
@@ -87184,7 +87203,7 @@ const TRIM = {
87184
87203
  description: _t("Removes space characters."),
87185
87204
  args: [arg("text (string)", _t("The text or reference to a cell containing text to be trimmed."))],
87186
87205
  compute: function(text) {
87187
- return trimContent(toString(text));
87206
+ return trimContent(toLocaleString(text, this.locale));
87188
87207
  },
87189
87208
  isExported: true
87190
87209
  };
@@ -87192,7 +87211,7 @@ const UPPER = {
87192
87211
  description: _t("Converts a specified string to uppercase."),
87193
87212
  args: [arg("text (string)", _t("The string to convert to uppercase."))],
87194
87213
  compute: function(text) {
87195
- return toString(text).toUpperCase();
87214
+ return toLocaleString(text, this.locale).toUpperCase();
87196
87215
  },
87197
87216
  isExported: true
87198
87217
  };
@@ -87289,7 +87308,7 @@ const HYPERLINK = {
87289
87308
  args: [arg("url (string)", _t("The full URL of the link enclosed in quotation marks.")), arg("link_label (string, optional)", _t("The text to display in the cell, enclosed in quotation marks."))],
87290
87309
  compute: function(url, linkLabel) {
87291
87310
  const processedUrl = toString(url).trim();
87292
- const processedLabel = toString(linkLabel) || processedUrl;
87311
+ const processedLabel = toLocaleString(linkLabel, this.locale) || processedUrl;
87293
87312
  if (processedUrl === "") return processedLabel;
87294
87313
  return markdownLink(processedLabel, processedUrl);
87295
87314
  },
@@ -87644,6 +87663,6 @@ const chartHelpers = {
87644
87663
  //#endregion
87645
87664
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, BadExpressionError, CHART_TYPES, CellErrorType, CellValueType, CircularDependencyError, ClientDisconnectedError, ClipboardMIMEType, CommandResult, CompiledFormula, CorePlugin, CoreViewPlugin, DEFAULT_LOCALE, DEFAULT_LOCALES, DEFAULT_LOCALE_DIGIT_GROUPING, DIRECTION, DispatchResult, DivisionByZeroError, EvaluationError, InvalidReferenceError, LocalTransportService, Model, NEXT_VALUE, NotAvailableError, NumberTooLargeError, OrderedLayers, PREVIOUS_VALUE, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, SplillBlockedError, Spreadsheet, SpreadsheetPivotTable, UIPlugin, UnknownFunctionError, __info__, addFunction, addRenderingLayer, astToFormula, availableConditionalFormatOperators, availableDataValidationOperators, availableFiltersOperators, borderPositions, borderStyles, canExecuteInReadonly, categories, chartHelpers, compatibility, components, composerFocusTypes, constants, convertAstNodes, coreTypes, createAutocompleteArgumentsProvider, errorTypes, filterDateCriterionOperators, filterNumberCriterionOperators, filterTextCriterionOperators, findCellInNewZone, functionCache, getCaretDownSvg, getCaretUpSvg, helpers, hooks, invalidSubtotalFormulasCommands, invalidateBordersCommands, invalidateCFEvaluationCommands, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, isCoreCommand, isHeadersDependant, isMatrix, isPositionDependent, isRangeDependant, isSheetDependent, isTargetDependent, isZoneDependent, iterateAstNodes, links, load, lockedSheetAllowedCommands, parse, parseTokens, readonlyAllowedCommands, registries, schemeToColorScale, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
87646
87665
 
87647
- __info__.version = "19.4.7";
87648
- __info__.date = "2026-08-12T09:16:40.949Z";
87649
- __info__.hash = "65642fe";
87666
+ __info__.version = "19.4.9";
87667
+ __info__.date = "2026-08-21T15:33:39.385Z";
87668
+ __info__.hash = "b48dbb3";