UPDATE: Adds bindings to update timezone and locale

UPDATE: Update "generate locale" utility

FIX: Minor fixes to UI and proper support for locales/timezones

UPDATE: Adds "display language" setting to core
This commit is contained in:
Nicolás Hatcher
2025-11-28 21:21:19 +01:00
parent 402a13bd00
commit ffe5d1a158
109 changed files with 4783 additions and 3216 deletions

View File

@@ -40,6 +40,18 @@ pub fn quote_name(name: &str) -> String {
quote_name_ic(name)
}
/// Gets all timezones
#[wasm_bindgen(js_name = "getAllTimezones")]
pub fn get_all_timezones() -> Vec<String> {
ironcalc_base::get_all_timezones()
}
/// Gets all supported locales
#[wasm_bindgen(js_name = "getSupportedLocales")]
pub fn get_supported_locales() -> Vec<String> {
ironcalc_base::get_supported_locales()
}
#[derive(Serialize)]
struct DefinedName {
name: String,
@@ -55,13 +67,19 @@ pub struct Model {
#[wasm_bindgen]
impl Model {
#[wasm_bindgen(constructor)]
pub fn new(name: &str, locale: &str, timezone: &str) -> Result<Model, JsError> {
let model = BaseModel::new_empty(name, locale, timezone).map_err(to_js_error)?;
pub fn new(
name: &str,
locale: &str,
timezone: &str,
language_id: &str,
) -> Result<Model, JsError> {
let model =
BaseModel::new_empty(name, locale, timezone, language_id).map_err(to_js_error)?;
Ok(Model { model })
}
pub fn from_bytes(bytes: &[u8]) -> Result<Model, JsError> {
let model = BaseModel::from_bytes(bytes).map_err(to_js_error)?;
pub fn from_bytes(bytes: &[u8], language_id: &str) -> Result<Model, JsError> {
let model = BaseModel::from_bytes(bytes, language_id).map_err(to_js_error)?;
Ok(Model { model })
}
@@ -788,4 +806,44 @@ impl Model {
Err(e) => Err(to_js_error(e.to_string())),
}
}
#[wasm_bindgen(js_name = "setTimezone")]
pub fn set_timezone(&mut self, timezone: &str) -> Result<(), JsError> {
self.model
.set_timezone(timezone)
.map_err(|e| to_js_error(e.to_string()))
}
#[wasm_bindgen(js_name = "setLocale")]
pub fn set_locale(&mut self, locale: &str) -> Result<(), JsError> {
self.model
.set_locale(locale)
.map_err(|e| to_js_error(e.to_string()))
}
/// Gets the timezone of the model
#[wasm_bindgen(js_name = "getTimezone")]
pub fn get_timezone(&self) -> String {
self.model.get_timezone()
}
/// Gets the locale of the model
#[wasm_bindgen(js_name = "getLocale")]
pub fn get_locale(&self) -> String {
self.model.get_locale()
}
/// Gets the language of the model
#[wasm_bindgen(js_name = "getLanguage")]
pub fn get_language(&self) -> String {
self.model.get_language()
}
/// Sets the language of the model
#[wasm_bindgen(js_name = "setLanguage")]
pub fn set_language(&mut self, language: &str) -> Result<(), JsError> {
self.model
.set_language(language)
.map_err(|e| to_js_error(e.to_string()))
}
}

View File

@@ -5,7 +5,7 @@ import { Model } from "../pkg/wasm.js";
const DEFAULT_ROW_HEIGHT = 28;
test('Frozen rows and columns', () => {
let model = new Model('Workbook1', 'en', 'UTC');
let model = new Model('Workbook1', 'en', 'UTC', 'en');
assert.strictEqual(model.getFrozenRowsCount(0), 0);
assert.strictEqual(model.getFrozenColumnsCount(0), 0);
@@ -17,7 +17,7 @@ test('Frozen rows and columns', () => {
});
test('Row height', () => {
let model = new Model('Workbook1', 'en', 'UTC');
let model = new Model('Workbook1', 'en', 'UTC', 'en');
assert.strictEqual(model.getRowHeight(0, 3), DEFAULT_ROW_HEIGHT);
model.setRowsHeight(0, 3, 3, 32);
@@ -34,7 +34,7 @@ test('Row height', () => {
});
test('Evaluates correctly', (t) => {
const model = new Model('Workbook1', 'en', 'UTC');
const model = new Model('Workbook1', 'en', 'UTC', 'en');
model.setUserInput(0, 1, 1, "23");
model.setUserInput(0, 1, 2, "=A1*3+1");
@@ -43,7 +43,7 @@ test('Evaluates correctly', (t) => {
});
test('Styles work', () => {
const model = new Model('Workbook1', 'en', 'UTC');
const model = new Model('Workbook1', 'en', 'UTC', 'en');
let style = model.getCellStyle(0, 1, 1);
assert.deepEqual(style, {
num_fmt: 'general',
@@ -76,7 +76,7 @@ test('Styles work', () => {
});
test("Add sheets", (t) => {
const model = new Model('Workbook1', 'en', 'UTC');
const model = new Model('Workbook1', 'en', 'UTC', 'en');
model.newSheet();
model.renameSheet(1, "NewName");
let props = model.getWorksheetsProperties();
@@ -94,7 +94,7 @@ test("Add sheets", (t) => {
});
test("invalid sheet index throws an exception", () => {
const model = new Model('Workbook1', 'en', 'UTC');
const model = new Model('Workbook1', 'en', 'UTC', 'en');
assert.throws(() => {
model.setRowsHeight(1, 1, 1, 100);
}, {
@@ -104,7 +104,7 @@ test("invalid sheet index throws an exception", () => {
});
test("invalid column throws an exception", () => {
const model = new Model('Workbook1', 'en', 'UTC');
const model = new Model('Workbook1', 'en', 'UTC', 'en');
assert.throws(() => {
model.setRowsHeight(0, -1, 0, 100);
}, {
@@ -114,7 +114,7 @@ test("invalid column throws an exception", () => {
});
test("floating column numbers get truncated", () => {
const model = new Model('Workbook1', 'en', 'UTC');
const model = new Model('Workbook1', 'en', 'UTC', 'en');
model.setRowsHeight(0.8, 5.2, 5.5, 100.5);
assert.strictEqual(model.getRowHeight(0.11, 5.99), 100.5);
@@ -122,7 +122,7 @@ test("floating column numbers get truncated", () => {
});
test("autofill", () => {
const model = new Model('Workbook1', 'en', 'UTC');
const model = new Model('Workbook1', 'en', 'UTC', 'en');
model.setUserInput(0, 1, 1, "23");
model.autoFillRows({sheet: 0, row: 1, column: 1, width: 1, height: 1}, 2);
@@ -131,7 +131,7 @@ test("autofill", () => {
});
test('insertRows shifts cells', () => {
const model = new Model('Workbook1', 'en', 'UTC');
const model = new Model('Workbook1', 'en', 'UTC', 'en');
model.setUserInput(0, 1, 1, '42');
model.insertRows(0, 1, 1);
@@ -140,7 +140,7 @@ test('insertRows shifts cells', () => {
});
test('insertColumns shifts cells', () => {
const model = new Model('Workbook1', 'en', 'UTC');
const model = new Model('Workbook1', 'en', 'UTC', 'en');
model.setUserInput(0, 1, 1, 'A');
model.setUserInput(0, 1, 2, 'B');
@@ -151,7 +151,7 @@ test('insertColumns shifts cells', () => {
});
test('deleteRows removes cells', () => {
const model = new Model('Workbook1', 'en', 'UTC');
const model = new Model('Workbook1', 'en', 'UTC', 'en');
model.setUserInput(0, 1, 1, '1');
model.setUserInput(0, 2, 1, '2');
@@ -162,7 +162,7 @@ test('deleteRows removes cells', () => {
});
test('deleteColumns removes cells', () => {
const model = new Model('Workbook1', 'en', 'UTC');
const model = new Model('Workbook1', 'en', 'UTC', 'en');
model.setUserInput(0, 1, 1, 'A');
model.setUserInput(0, 1, 2, 'B');
@@ -173,7 +173,7 @@ test('deleteColumns removes cells', () => {
});
test("move row", () => {
const model = new Model('Workbook1', 'en', 'UTC');
const model = new Model('Workbook1', 'en', 'UTC', 'en');
model.setUserInput(0, 3, 5, "=G3");
model.setUserInput(0, 4, 5, "=G4");
model.setUserInput(0, 5, 5, "=SUM(G3:J3)");
@@ -192,7 +192,7 @@ test("move row", () => {
});
test("move column", () => {
const model = new Model('Workbook1', 'en', 'UTC');
const model = new Model('Workbook1', 'en', 'UTC', 'en');
model.setUserInput(0, 3, 5, "=G3");
model.setUserInput(0, 4, 5, "=H3");
model.setUserInput(0, 5, 5, "=SUM(G3:J7)");