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:
@@ -4,7 +4,7 @@ use ironcalc::{
|
||||
};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut model = Model::new_empty("hello-calc.xlsx", "en", "UTC")?;
|
||||
let mut model = Model::new_empty("hello-calc.xlsx", "en", "UTC", "en")?;
|
||||
// Adds a square of numbers in the first sheet
|
||||
for row in 1..100 {
|
||||
for column in 1..100 {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use ironcalc::{base::Model, export::save_to_xlsx};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut model = Model::new_empty("hello_styles", "en", "UTC")?;
|
||||
let mut model = Model::new_empty("hello_styles", "en", "UTC", "en")?;
|
||||
|
||||
// We are going to change styles in cell A1
|
||||
let (sheet, row, column) = (0, 1, 1);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use ironcalc::{base::Model, export::save_to_xlsx};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut model = Model::new_empty("widths-and-heights", "en", "UTC")?;
|
||||
let mut model = Model::new_empty("widths-and-heights", "en", "UTC", "en")?;
|
||||
// Cell C5
|
||||
let (sheet, row, column) = (0, 5, 3);
|
||||
// Make the first column 4 times as width
|
||||
|
||||
@@ -30,7 +30,7 @@ fn main() {
|
||||
let file_path = path::Path::new(file_name);
|
||||
let base_name = file_path.file_stem().unwrap().to_str().unwrap();
|
||||
let output_file_name = &format!("{base_name}.output.xlsx");
|
||||
let mut model = load_from_xlsx(file_name, "en", "UTC").unwrap();
|
||||
let mut model = load_from_xlsx(file_name, "en", "UTC", "en").unwrap();
|
||||
model.evaluate();
|
||||
println!("Saving result as: {output_file_name}. Please open with Excel and test.");
|
||||
save_to_xlsx(&model, output_file_name).unwrap();
|
||||
|
||||
@@ -29,6 +29,6 @@ fn main() {
|
||||
&format!("{base_name}.ic")
|
||||
};
|
||||
|
||||
let model = load_from_xlsx(file_name, "en", "UTC").unwrap();
|
||||
let model = load_from_xlsx(file_name, "en", "UTC", "en").unwrap();
|
||||
save_to_icalc(&model, output_file_name).unwrap();
|
||||
}
|
||||
|
||||
@@ -185,15 +185,15 @@ pub(crate) fn compare_models(m1: &Model, m2: &Model) -> Result<(), String> {
|
||||
|
||||
/// Tests that file in file_path produces the same results in Excel and in IronCalc.
|
||||
pub fn test_file(file_path: &str) -> Result<(), String> {
|
||||
let model1 = load_from_xlsx(file_path, "en", "UTC").unwrap();
|
||||
let mut model2 = load_from_xlsx(file_path, "en", "UTC").unwrap();
|
||||
let model1 = load_from_xlsx(file_path, "en", "UTC", "en").unwrap();
|
||||
let mut model2 = load_from_xlsx(file_path, "en", "UTC", "en").unwrap();
|
||||
model2.evaluate();
|
||||
compare_models(&model1, &model2)
|
||||
}
|
||||
|
||||
/// Tests that file in file_path can be converted to xlsx and read again
|
||||
pub fn test_load_and_saving(file_path: &str, temp_dir_name: &Path) -> Result<(), String> {
|
||||
let model1 = load_from_xlsx(file_path, "en", "UTC").unwrap();
|
||||
let model1 = load_from_xlsx(file_path, "en", "UTC", "en").unwrap();
|
||||
|
||||
let base_name = Path::new(file_path).file_name().unwrap().to_str().unwrap();
|
||||
|
||||
@@ -202,7 +202,7 @@ pub fn test_load_and_saving(file_path: &str, temp_dir_name: &Path) -> Result<(),
|
||||
// test can save
|
||||
save_to_xlsx(&model1, temp_file_path).unwrap();
|
||||
// test can open
|
||||
let mut model2 = load_from_xlsx(temp_file_path, "en", "UTC").unwrap();
|
||||
let mut model2 = load_from_xlsx(temp_file_path, "en", "UTC", "en").unwrap();
|
||||
model2.evaluate();
|
||||
compare_models(&model1, &model2)
|
||||
}
|
||||
@@ -214,9 +214,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn compare_different_sheets() {
|
||||
let mut model1 = Model::new_empty("model", "en", "UTC").unwrap();
|
||||
let mut model1 = Model::new_empty("model", "en", "UTC", "en").unwrap();
|
||||
model1.new_sheet();
|
||||
let model2 = Model::new_empty("model", "en", "UTC").unwrap();
|
||||
let model2 = Model::new_empty("model", "en", "UTC", "en").unwrap();
|
||||
|
||||
assert!(compare(&model1, &model2).is_err());
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::import::load_from_icalc;
|
||||
use crate::{export::save_to_xlsx, import::load_from_xlsx};
|
||||
|
||||
pub fn new_empty_model() -> Model {
|
||||
Model::new_empty("model", "en", "UTC").unwrap()
|
||||
Model::new_empty("model", "en", "UTC", "en").unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -42,7 +42,7 @@ fn test_values() {
|
||||
let temp_file_name = "temp_file_test_values.xlsx";
|
||||
save_to_xlsx(&model, temp_file_name).unwrap();
|
||||
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC", "en").unwrap();
|
||||
assert_eq!(model.get_formatted_cell_value(0, 1, 1).unwrap(), "123.456");
|
||||
assert_eq!(
|
||||
model.get_formatted_cell_value(0, 2, 1).unwrap(),
|
||||
@@ -66,7 +66,7 @@ fn test_values() {
|
||||
let temp_file_name = "temp_file_test_values.ic";
|
||||
save_to_icalc(&model, temp_file_name).unwrap();
|
||||
|
||||
let model = load_from_icalc(temp_file_name).unwrap();
|
||||
let model = load_from_icalc(temp_file_name, "en").unwrap();
|
||||
assert_eq!(model.get_formatted_cell_value(0, 1, 1).unwrap(), "123.456");
|
||||
assert_eq!(
|
||||
model.get_formatted_cell_value(0, 2, 1).unwrap(),
|
||||
@@ -95,7 +95,7 @@ fn frozen_rows() {
|
||||
model.evaluate();
|
||||
let temp_file_name = "temp_file_test_frozen_rows.xlsx";
|
||||
save_to_xlsx(&model, temp_file_name).unwrap();
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC", "en").unwrap();
|
||||
assert_eq!(model.get_frozen_rows_count(0).unwrap(), 23);
|
||||
fs::remove_file(temp_file_name).unwrap();
|
||||
}
|
||||
@@ -107,7 +107,7 @@ fn frozen_columns() {
|
||||
model.evaluate();
|
||||
let temp_file_name = "temp_file_test_frozen_columns.xlsx";
|
||||
save_to_xlsx(&model, temp_file_name).unwrap();
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC", "en").unwrap();
|
||||
assert_eq!(model.get_frozen_columns_count(0).unwrap(), 42);
|
||||
fs::remove_file(temp_file_name).unwrap();
|
||||
}
|
||||
@@ -120,7 +120,7 @@ fn frozen_rows_and_columns() {
|
||||
model.evaluate();
|
||||
let temp_file_name = "temp_file_test_frozen_rows_and_columns.xlsx";
|
||||
save_to_xlsx(&model, temp_file_name).unwrap();
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC", "en").unwrap();
|
||||
assert_eq!(model.get_frozen_rows_count(0).unwrap(), 23);
|
||||
assert_eq!(model.get_frozen_columns_count(0).unwrap(), 42);
|
||||
fs::remove_file(temp_file_name).unwrap();
|
||||
@@ -144,7 +144,7 @@ fn test_formulas() {
|
||||
let temp_file_name = "temp_file_test_formulas.xlsx";
|
||||
save_to_xlsx(&model, temp_file_name).unwrap();
|
||||
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC", "en").unwrap();
|
||||
assert_eq!(model.get_formatted_cell_value(0, 1, 2).unwrap(), "11");
|
||||
assert_eq!(model.get_formatted_cell_value(0, 2, 2).unwrap(), "13");
|
||||
assert_eq!(model.get_formatted_cell_value(0, 3, 2).unwrap(), "15");
|
||||
@@ -166,7 +166,7 @@ fn test_sheets() {
|
||||
let temp_file_name = "temp_file_test_sheets.xlsx";
|
||||
save_to_xlsx(&model, temp_file_name).unwrap();
|
||||
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC", "en").unwrap();
|
||||
assert_eq!(
|
||||
model.workbook.get_worksheet_names(),
|
||||
vec!["Sheet1", "With space", "Tango & Cash", "你好世界"]
|
||||
@@ -195,7 +195,7 @@ fn test_named_styles() {
|
||||
let temp_file_name = "temp_file_test_named_styles.xlsx";
|
||||
save_to_xlsx(&model, temp_file_name).unwrap();
|
||||
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC", "en").unwrap();
|
||||
assert!(model
|
||||
.workbook
|
||||
.styles
|
||||
|
||||
@@ -140,16 +140,21 @@ pub fn load_from_xlsx_bytes(
|
||||
}
|
||||
|
||||
/// Loads a [Model] from an xlsx file
|
||||
pub fn load_from_xlsx(file_name: &str, locale: &str, tz: &str) -> Result<Model, XlsxError> {
|
||||
pub fn load_from_xlsx(
|
||||
file_name: &str,
|
||||
locale: &str,
|
||||
tz: &str,
|
||||
language: &str,
|
||||
) -> Result<Model, XlsxError> {
|
||||
let workbook = load_from_excel(file_name, locale, tz)?;
|
||||
Model::from_workbook(workbook).map_err(XlsxError::Workbook)
|
||||
Model::from_workbook(workbook, language).map_err(XlsxError::Workbook)
|
||||
}
|
||||
|
||||
/// Loads a [Model] from an `ic` file (a file in the IronCalc internal representation)
|
||||
pub fn load_from_icalc(file_name: &str) -> Result<Model, XlsxError> {
|
||||
pub fn load_from_icalc(file_name: &str, language_id: &str) -> Result<Model, XlsxError> {
|
||||
let contents = fs::read(file_name)
|
||||
.map_err(|e| XlsxError::IO(format!("Could not extract workbook name: {e}")))?;
|
||||
let workbook: Workbook = bitcode::decode(&contents)
|
||||
.map_err(|e| XlsxError::IO(format!("Failed to decode file: {e}")))?;
|
||||
Model::from_workbook(workbook).map_err(XlsxError::Workbook)
|
||||
Model::from_workbook(workbook, language_id).map_err(XlsxError::Workbook)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use ironcalc_base::expressions::parser::static_analysis::add_implicit_intersection;
|
||||
use ironcalc_base::expressions::parser::{
|
||||
new_parser_english, static_analysis::add_implicit_intersection,
|
||||
};
|
||||
use std::{collections::HashMap, io::Read, num::ParseIntError};
|
||||
|
||||
use ironcalc_base::{
|
||||
expressions::{
|
||||
parser::{stringify::to_rc_format, DefinedNameS, Parser},
|
||||
parser::{stringify::to_rc_format, DefinedNameS},
|
||||
token::{get_error_by_english_name, Error},
|
||||
types::CellReferenceRC,
|
||||
utils::{column_to_number, parse_reference_a1},
|
||||
@@ -304,7 +306,7 @@ fn from_a1_to_rc(
|
||||
tables: HashMap<String, Table>,
|
||||
defined_names: Vec<DefinedNameS>,
|
||||
) -> Result<String, XlsxError> {
|
||||
let mut parser = Parser::new(worksheets.to_owned(), defined_names, tables);
|
||||
let mut parser = new_parser_english(worksheets.to_owned(), defined_names, tables);
|
||||
let cell_reference =
|
||||
parse_reference(&context).map_err(|error| XlsxError::Xml(error.to_string()))?;
|
||||
let mut t = parser.parse(&formula, &cell_reference);
|
||||
|
||||
@@ -15,7 +15,7 @@ use ironcalc_base::{Model, UserModel};
|
||||
// We check that the output of example.xlsx is what we expect.
|
||||
#[test]
|
||||
fn test_example() {
|
||||
let model = load_from_xlsx("tests/example.xlsx", "en", "UTC").unwrap();
|
||||
let model = load_from_xlsx("tests/example.xlsx", "en", "UTC", "en").unwrap();
|
||||
// We should use the API once it is in place
|
||||
let workbook = model.workbook;
|
||||
let ws = &workbook.worksheets;
|
||||
@@ -47,7 +47,7 @@ fn test_example() {
|
||||
assert_eq!(ws[0].views[&0].column, 5);
|
||||
assert_eq!(ws[0].views[&0].range, [13, 5, 20, 14]);
|
||||
|
||||
let model2 = load_from_icalc("tests/example.ic").unwrap();
|
||||
let model2 = load_from_icalc("tests/example.ic", "en").unwrap();
|
||||
let _ = bitcode::encode(&model2.workbook);
|
||||
assert_eq!(workbook, model2.workbook);
|
||||
}
|
||||
@@ -64,7 +64,7 @@ fn test_load_from_xlsx_bytes() {
|
||||
|
||||
#[test]
|
||||
fn no_grid() {
|
||||
let model = load_from_xlsx("tests/NoGrid.xlsx", "en", "UTC").unwrap();
|
||||
let model = load_from_xlsx("tests/NoGrid.xlsx", "en", "UTC", "en").unwrap();
|
||||
{
|
||||
let workbook = &model.workbook;
|
||||
let ws = &workbook.worksheets;
|
||||
@@ -87,7 +87,7 @@ fn no_grid() {
|
||||
// save it and check again
|
||||
let temp_file_name = "temp_file_no_grid.xlsx";
|
||||
save_to_xlsx(&model, temp_file_name).unwrap();
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC", "en").unwrap();
|
||||
let workbook = &model.workbook;
|
||||
let ws = &workbook.worksheets;
|
||||
|
||||
@@ -110,13 +110,13 @@ fn no_grid() {
|
||||
|
||||
#[test]
|
||||
fn test_save_to_xlsx() {
|
||||
let mut model = load_from_xlsx("tests/example.xlsx", "en", "UTC").unwrap();
|
||||
let mut model = load_from_xlsx("tests/example.xlsx", "en", "UTC", "en").unwrap();
|
||||
model.evaluate();
|
||||
let temp_file_name = "temp_file_example.xlsx";
|
||||
// test can safe
|
||||
save_to_xlsx(&model, temp_file_name).unwrap();
|
||||
// test can open
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC", "en").unwrap();
|
||||
let metadata = &model.workbook.metadata;
|
||||
assert_eq!(metadata.application, "IronCalc Sheets");
|
||||
// FIXME: This will need to be updated once we fix versioning
|
||||
@@ -142,7 +142,7 @@ fn test_save_to_xlsx() {
|
||||
#[test]
|
||||
fn test_freeze() {
|
||||
// freeze has 3 frozen columns and 2 frozen rows
|
||||
let model = load_from_xlsx("tests/freeze.xlsx", "en", "UTC")
|
||||
let model = load_from_xlsx("tests/freeze.xlsx", "en", "UTC", "en")
|
||||
.unwrap()
|
||||
.workbook;
|
||||
assert_eq!(model.worksheets[0].frozen_rows, 2);
|
||||
@@ -152,7 +152,7 @@ fn test_freeze() {
|
||||
#[test]
|
||||
fn test_split() {
|
||||
// We test that a workbook with split panes do not produce frozen rows and columns
|
||||
let model = load_from_xlsx("tests/split.xlsx", "en", "UTC")
|
||||
let model = load_from_xlsx("tests/split.xlsx", "en", "UTC", "en")
|
||||
.unwrap()
|
||||
.workbook;
|
||||
assert_eq!(model.worksheets[0].frozen_rows, 0);
|
||||
@@ -290,14 +290,14 @@ fn test_model_has_correct_styles(model: &Model) {
|
||||
|
||||
#[test]
|
||||
fn test_simple_text() {
|
||||
let model = load_from_xlsx("tests/basic_text.xlsx", "en", "UTC").unwrap();
|
||||
let model = load_from_xlsx("tests/basic_text.xlsx", "en", "UTC", "en").unwrap();
|
||||
|
||||
test_model_has_correct_styles(&model);
|
||||
|
||||
let temp_file_name = "temp_file_test_named_styles.xlsx";
|
||||
save_to_xlsx(&model, temp_file_name).unwrap();
|
||||
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
|
||||
let model = load_from_xlsx(temp_file_name, "en", "UTC", "en").unwrap();
|
||||
fs::remove_file(temp_file_name).unwrap();
|
||||
test_model_has_correct_styles(&model);
|
||||
}
|
||||
@@ -305,10 +305,10 @@ fn test_simple_text() {
|
||||
#[test]
|
||||
fn test_defined_names_casing() {
|
||||
let test_file_path = "tests/calc_tests/defined_names_for_unit_test.xlsx";
|
||||
let loaded_workbook = load_from_xlsx(test_file_path, "en", "UTC")
|
||||
let loaded_workbook = load_from_xlsx(test_file_path, "en", "UTC", "en")
|
||||
.unwrap()
|
||||
.workbook;
|
||||
let mut model = Model::from_bytes(&bitcode::encode(&loaded_workbook)).unwrap();
|
||||
let mut model = Model::from_bytes(&bitcode::encode(&loaded_workbook), "en").unwrap();
|
||||
|
||||
let (row, column) = (2, 13); // B13
|
||||
let test_cases = [
|
||||
@@ -455,7 +455,7 @@ fn test_exporting_merged_cells() {
|
||||
let expected_merge_cell_ref = {
|
||||
// loading the xlsx file containing merged cells
|
||||
let example_file_name = "tests/example.xlsx";
|
||||
let mut model = load_from_xlsx(example_file_name, "en", "UTC").unwrap();
|
||||
let mut model = load_from_xlsx(example_file_name, "en", "UTC", "en").unwrap();
|
||||
let expected_merge_cell_ref = model
|
||||
.workbook
|
||||
.worksheets
|
||||
@@ -469,7 +469,7 @@ fn test_exporting_merged_cells() {
|
||||
expected_merge_cell_ref
|
||||
};
|
||||
{
|
||||
let mut temp_model = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
|
||||
let mut temp_model = load_from_xlsx(temp_file_name, "en", "UTC", "en").unwrap();
|
||||
{
|
||||
// loading the previous file back and verifying whether
|
||||
// merged cells got exported properly or not
|
||||
@@ -496,7 +496,7 @@ fn test_exporting_merged_cells() {
|
||||
.clear();
|
||||
|
||||
save_to_xlsx(&temp_model, temp_file_name).unwrap();
|
||||
let temp_model2 = load_from_xlsx(temp_file_name, "en", "UTC").unwrap();
|
||||
let temp_model2 = load_from_xlsx(temp_file_name, "en", "UTC", "en").unwrap();
|
||||
let got_merge_cell_ref_cnt = &temp_model2
|
||||
.workbook
|
||||
.worksheets
|
||||
@@ -599,7 +599,7 @@ fn test_documentation_xlsx() {
|
||||
#[test]
|
||||
fn test_user_model() {
|
||||
let temp_file_name = "temp_file_test_user_model.xlsx";
|
||||
let mut model = UserModel::new_empty("my_model", "en", "UTC").unwrap();
|
||||
let mut model = UserModel::new_empty("my_model", "en", "UTC", "en").unwrap();
|
||||
model.set_user_input(0, 1, 1, "=1+1").unwrap();
|
||||
|
||||
// test we can use `get_model` to save the model
|
||||
@@ -627,7 +627,7 @@ fn test_user_model() {
|
||||
// wb.save('openpyxl_example.xlsx')
|
||||
#[test]
|
||||
fn test_pyopenxl_example() {
|
||||
let mut model = load_from_xlsx("tests/openpyxl_example.xlsx", "en", "UTC").unwrap();
|
||||
let mut model = load_from_xlsx("tests/openpyxl_example.xlsx", "en", "UTC", "en").unwrap();
|
||||
model.evaluate();
|
||||
|
||||
let a1 = model.get_formatted_cell_value(0, 1, 1).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user