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

@@ -1,6 +1,6 @@
import ironcalc as ic
model = ic.create("model", "en", "UTC")
model = ic.create("model", "en", "UTC", "en")
model.set_user_input(0, 1, 1, "=21*2")
model.evaluate()

View File

@@ -9,7 +9,7 @@ Creating an Empty Model
import ironcalc as ic
model = ic.create("My Workbook", "en", "UTC")
model = ic.create("My Workbook", "en", "UTC", "en")
Loading from XLSX
^^^^^^^^^^^^^^^^^
@@ -18,14 +18,14 @@ Loading from XLSX
import ironcalc as ic
model = ic.load_from_xlsx("example.xlsx", "en", "UTC")
model = ic.load_from_xlsx("example.xlsx", "en", "UTC", "en")
Modifying and Saving
^^^^^^^^^^^^^^^^^^^^
.. code-block:: python
model = ic.create("model", "en", "UTC")
model = ic.create("model", "en", "UTC", "en")
model.set_user_input(0, 1, 1, "123")
model.set_user_input(0, 1, 2, "=A1*2")
model.evaluate()

View File

@@ -139,7 +139,7 @@ impl PyModel {
/// Get raw value
pub fn get_cell_content(&self, sheet: u32, row: i32, column: i32) -> PyResult<String> {
self.model
.get_cell_content(sheet, row, column)
.get_localized_cell_content(sheet, row, column)
.map_err(|e| WorkbookError::new_err(e.to_string()))
}
@@ -329,17 +329,22 @@ impl PyModel {
/// Loads a function from an xlsx file
#[pyfunction]
pub fn load_from_xlsx(file_path: &str, locale: &str, tz: &str) -> PyResult<PyModel> {
let model = import::load_from_xlsx(file_path, locale, tz)
pub fn load_from_xlsx(
file_path: &str,
locale: &str,
tz: &str,
language_id: &str,
) -> PyResult<PyModel> {
let model = import::load_from_xlsx(file_path, locale, tz, language_id)
.map_err(|e| WorkbookError::new_err(e.to_string()))?;
Ok(PyModel { model })
}
/// Loads a function from icalc binary representation
#[pyfunction]
pub fn load_from_icalc(file_name: &str) -> PyResult<PyModel> {
let model =
import::load_from_icalc(file_name).map_err(|e| WorkbookError::new_err(e.to_string()))?;
pub fn load_from_icalc(file_name: &str, language_id: &str) -> PyResult<PyModel> {
let model = import::load_from_icalc(file_name, language_id)
.map_err(|e| WorkbookError::new_err(e.to_string()))?;
Ok(PyModel { model })
}
@@ -347,26 +352,31 @@ pub fn load_from_icalc(file_name: &str) -> PyResult<PyModel> {
/// This function expects the bytes to be in the internal binary ic format
/// which is the same format used by the `save_to_icalc` function.
#[pyfunction]
pub fn load_from_bytes(bytes: &[u8]) -> PyResult<PyModel> {
pub fn load_from_bytes(bytes: &[u8], language_id: &str) -> PyResult<PyModel> {
let workbook: Workbook =
bitcode::decode(bytes).map_err(|e| WorkbookError::new_err(e.to_string()))?;
let model =
Model::from_workbook(workbook).map_err(|e| WorkbookError::new_err(e.to_string()))?;
let model = Model::from_workbook(workbook, language_id)
.map_err(|e| WorkbookError::new_err(e.to_string()))?;
Ok(PyModel { model })
}
/// Creates an empty model in the raw API
#[pyfunction]
pub fn create(name: &str, locale: &str, tz: &str) -> PyResult<PyModel> {
let model =
Model::new_empty(name, locale, tz).map_err(|e| WorkbookError::new_err(e.to_string()))?;
pub fn create(name: &str, locale: &str, tz: &str, language_id: &str) -> PyResult<PyModel> {
let model = Model::new_empty(name, locale, tz, language_id)
.map_err(|e| WorkbookError::new_err(e.to_string()))?;
Ok(PyModel { model })
}
/// Creates a model with the user model API
#[pyfunction]
pub fn create_user_model(name: &str, locale: &str, tz: &str) -> PyResult<PyUserModel> {
let model = UserModel::new_empty(name, locale, tz)
pub fn create_user_model(
name: &str,
locale: &str,
tz: &str,
language_id: &str,
) -> PyResult<PyUserModel> {
let model = UserModel::new_empty(name, locale, tz, language_id)
.map_err(|e| WorkbookError::new_err(e.to_string()))?;
Ok(PyUserModel { model })
}
@@ -377,8 +387,9 @@ pub fn create_user_model_from_xlsx(
file_path: &str,
locale: &str,
tz: &str,
language_id: &str,
) -> PyResult<PyUserModel> {
let model = import::load_from_xlsx(file_path, locale, tz)
let model = import::load_from_xlsx(file_path, locale, tz, language_id)
.map_err(|e| WorkbookError::new_err(e.to_string()))?;
let model = UserModel::from_model(model);
Ok(PyUserModel { model })
@@ -386,9 +397,9 @@ pub fn create_user_model_from_xlsx(
/// Creates a user model from an icalc file
#[pyfunction]
pub fn create_user_model_from_icalc(file_name: &str) -> PyResult<PyUserModel> {
let model =
import::load_from_icalc(file_name).map_err(|e| WorkbookError::new_err(e.to_string()))?;
pub fn create_user_model_from_icalc(file_name: &str, language_id: &str) -> PyResult<PyUserModel> {
let model = import::load_from_icalc(file_name, language_id)
.map_err(|e| WorkbookError::new_err(e.to_string()))?;
let model = UserModel::from_model(model);
Ok(PyUserModel { model })
}
@@ -397,11 +408,11 @@ pub fn create_user_model_from_icalc(file_name: &str) -> PyResult<PyUserModel> {
/// This function expects the bytes to be in the internal binary ic format
/// which is the same format used by the `save_to_icalc` function.
#[pyfunction]
pub fn create_user_model_from_bytes(bytes: &[u8]) -> PyResult<PyUserModel> {
pub fn create_user_model_from_bytes(bytes: &[u8], language_id: &str) -> PyResult<PyUserModel> {
let workbook: Workbook =
bitcode::decode(bytes).map_err(|e| WorkbookError::new_err(e.to_string()))?;
let model =
Model::from_workbook(workbook).map_err(|e| WorkbookError::new_err(e.to_string()))?;
let model = Model::from_workbook(workbook, language_id)
.map_err(|e| WorkbookError::new_err(e.to_string()))?;
let user_model = UserModel::from_model(model);
Ok(PyUserModel { model: user_model })
}

View File

@@ -1,7 +1,7 @@
import ironcalc as ic
def test_simple():
model = ic.create("model", "en", "UTC")
model = ic.create("model", "en", "UTC", "en")
model.set_user_input(0, 1, 1, "=1+2")
model.evaluate()
@@ -9,12 +9,12 @@ def test_simple():
bytes = model.to_bytes()
model2 = ic.load_from_bytes(bytes)
model2 = ic.load_from_bytes(bytes, "en")
assert model2.get_formatted_cell_value(0, 1, 1) == "3"
def test_simple_user():
model = ic.create_user_model("model", "en", "UTC")
model = ic.create_user_model("model", "en", "UTC", "en")
model.set_user_input(0, 1, 1, "=1+2")
model.set_user_input(0, 1, 2, "=A1+3")
@@ -23,7 +23,7 @@ def test_simple_user():
diffs = model.flush_send_queue()
model2 = ic.create_user_model("model", "en", "UTC")
model2 = ic.create_user_model("model", "en", "UTC", "en")
model2.apply_external_diffs(diffs)
assert model2.get_formatted_cell_value(0, 1, 1) == "3"
assert model2.get_formatted_cell_value(0, 1, 2) == "6"
@@ -31,7 +31,7 @@ def test_simple_user():
def test_sheet_dimensions():
# Test with empty sheet
model = ic.create("model", "en", "UTC")
model = ic.create("model", "en", "UTC", "en")
min_row, max_row, min_col, max_col = model.get_sheet_dimensions(0)
assert (min_row, max_row, min_col, max_col) == (1, 1, 1, 1)
@@ -47,7 +47,7 @@ def test_sheet_dimensions():
def test_sheet_dimensions_user_model():
# Test with user model API as well
model = ic.create_user_model("model", "en", "UTC")
model = ic.create_user_model("model", "en", "UTC", "en")
# Add a single cell
model.set_user_input(0, 2, 3, "Test")