diff --git a/api/rs/slint/private_unstable_api.rs b/api/rs/slint/private_unstable_api.rs index f3f66db5260..6c1f1f78255 100644 --- a/api/rs/slint/private_unstable_api.rs +++ b/api/rs/slint/private_unstable_api.rs @@ -211,6 +211,7 @@ pub mod re_exports { pub use i_slint_core::string::shared_string_from_number; pub use i_slint_core::string::shared_string_from_number_fixed; pub use i_slint_core::string::shared_string_from_number_precision; + pub use i_slint_core::string::shared_string_from_number_unlocalized; pub use i_slint_core::timers::{Timer, TimerMode}; pub use i_slint_core::translations::{ set_bundled_languages, translate_from_bundle, translate_from_bundle_with_plural, diff --git a/cspell.json b/cspell.json index 73df0d2ee02..3b61227f891 100644 --- a/cspell.json +++ b/cspell.json @@ -1,348 +1,351 @@ { - "version": "0.2", - "language": "en", - "languageSettings": [ - { - "languageId": "rust", - "words": [ - "bbox", - "bindgen", - "boxshadowcache", - "builtins", - "canonicalize", // std::path::Path::canonicalize - "codemap", - "concat", - "Consts", - "evenodd", - "FBOs", // plural of FBO (frame buffer object) - "fontdb", - "fullscreen", - "glutin", - "glutin's", - "maxx", - "maxy", - "minx", - "miny", - "miri", - "peekable", - "Realloc", - "refcell", - "rtti", - "Smol", - "smolstr", - "subspan", - "uninit", - "unmap", - "unsync", - "vsync" - ], - "ignoreRegExpList": [ - "/#\\[cfg\\b.+\\]/", - "/#\\[repr\\b.+\\]/", - // Exclude crate paths - "/(\\b|::)[a-z0-9_]+::/", - "/::[a-z0-9_]+(\\b|::)/", - // Qt things: - "/\\bQt_[a-zA-Z0-9_]+/" - ] - }, - { - "languageId": "restructuredtext", + "version": "0.2", + "language": "en", + "languageSettings": [ + { + "languageId": "rust", + "words": [ + "bbox", + "bindgen", + "boxshadowcache", + "builtins", + "canonicalize", // std::path::Path::canonicalize + "codemap", + "concat", + "Consts", + "evenodd", + "FBOs", // plural of FBO (frame buffer object) + "fontdb", + "fullscreen", + "glutin", + "glutin's", + "maxx", + "maxy", + "minx", + "miny", + "miri", + "peekable", + "Realloc", + "refcell", + "rtti", + "Smol", + "smolstr", + "subspan", + "uninit", + "unlocalized", + "Unlocalized", + "unmap", + "unsync", + "vsync" + ], + "ignoreRegExpList": [ + "/#\\[cfg\\b.+\\]/", + "/#\\[repr\\b.+\\]/", + // Exclude crate paths + "/(\\b|::)[a-z0-9_]+::/", + "/::[a-z0-9_]+(\\b|::)/", + // Qt things: + "/\\bQt_[a-zA-Z0-9_]+/" + ] + }, + { + "languageId": "restructuredtext", "words": [ "genindex" ], "ignoreRegExpList": [ "/:.+:/" ] - }, - { + }, + { "languageId": [ "markdown", "md", "mdx" ], - "words": [ - "DSLINT", - "Espressif", - "libname", - "linebuffer", - "mylibrary", - "mywidgets", - "otherlibrary", - "Lmylibrary", - "progressindicator", - "standardbutton", - "standardlistview", - "standardtableview", - "rustup", - "setdefault", - "Sonoma", - "SUBDIR", - "Yocto", - "relpath", - "classslint", - "vectormodel", - "structslint", - "namespaceslint", - "compilerconfiguration", - "componentweakhandle", - "listmodel", - "skiarenderer", - "softwarerenderer", - "tschüß", - "TSCHÜSS", - "ὈΔΥΣΣΕΎΣ", - "ὀδυσσεύς", - "commonmark", - "strikethroughs" - ] - } - ], - "words": [ - "aarch", - "AARRGGBB", - "accesskit", - "antialiasing", - "Argb", - "armv", - "astrojs", - "Bezier", - "Bézier", - "cbindgen", - "cdylib", - "cmake", - "colspan", - "combobox", - "radiobutton", - "contexte", - "cupertino", - "datastructures", - "dealloc", - "distros", - "embedders", - "espflash", - "Femto", - "femtovg", - "flexboxlayout", - "flickable", - "focusable", - "frameless", - "fullscreen", - "gles", - "Goffart", - "gradians", - "grayscale", - "gridlayout", - "groupbox", - "Hausmann", - "Helvetica", - "imagefilter", - "inout", - "knip", - "layouting", - "linebreak", - "lineedit", - "LINUXFB", - "listview", - "lvalue", - "mdns", - "microcontroller", - "microcontrollers", - "MSVC", - "muda", - "napi", - "ogoffart", - "oneshot", - "Oooops", - "opengl", - "opengles", - "Pandoc", - "pico", - "pixmap", - "prestart", - "printerdemo", - "pythonw", - "replacen", - "rehype", - "Rgba", - "riscv", - "rowspan", - "RRGGBB", - "RRGGBBAA", - "rustc", - "rustdoc", - "rustflags", - "rvalue", - "SANDBOXING", - "scrollview", - "SDK", - "seti", - "sixtyfps", - "skia", - "slint", - "slintdoc", - "slintdocs", - "slintpad", - "spdx", - "spinbox", - "Srgb", - "streetsidesoftware", - "tableview", - "tabwidget", - "testcase", - "textedit", - "tmpobj", - "toolchain", - "toolkit", - "Toradex", - "touchpad", - "trackpad", - "trackpads", - "tronical", - "typeloader", - "uefi", - "uncompiled", - "Unshiftable", - "unerase", - "unmapping", - "unminimize", - "untracked", - "viewbox", - "virtualizes", - "Vivante", - "vtable", - "vulkan", - "wasm", - "webassembly", - "wgpu", - "windowrc", - "winit", - "xaarrggbb", - "Xcodegen", - "Xcodeproj", - "xtask", - "xtensa", - // CSS Color 4 named-color keywords not accepted by the default English dictionary (W3C CSS Color Module Level 4). - "aliceblue", - "antiquewhite", - "blanchedalmond", - "blueviolet", - "burlywood", - "cadetblue", - "cornflowerblue", - "cornsilk", - "darkcyan", - "darkgoldenrod", - "darkgray", - "darkgreen", - "darkgrey", - "darkkhaki", - "darkmagenta", - "darkolivegreen", - "darkorange", - "darkorchid", - "darkred", - "darksalmon", - "darkseagreen", - "darkslateblue", - "darkslategray", - "darkslategrey", - "darkturquoise", - "darkviolet", - "deeppink", - "deepskyblue", - "dimgray", - "dimgrey", - "dodgerblue", - "floralwhite", - "forestgreen", - "gainsboro", - "ghostwhite", - "greenyellow", - "hotpink", - "indianred", - "lavenderblush", - "lawngreen", - "lemonchiffon", - "lightcoral", - "lightcyan", - "lightgoldenrodyellow", - "lightgray", - "lightgreen", - "lightpink", - "lightsalmon", - "lightseagreen", - "lightskyblue", - "lightslategray", - "lightslategrey", - "lightsteelblue", - "lightyellow", - "limegreen", - "mediumaquamarine", - "mediumblue", - "mediumorchid", - "mediumpurple", - "mediumseagreen", - "mediumslateblue", - "mediumspringgreen", - "mediumturquoise", - "mediumvioletred", - "midnightblue", - "mintcream", - "mistyrose", - "navajowhite", - "oldlace", - "olivedrab", - "orangered", - "palegoldenrod", - "palegreen", - "paleturquoise", - "palevioletred", - "papayawhip", - "peachpuff", - "powderblue", - "rebeccapurple", - "rosybrown", - "royalblue", - "saddlebrown", - "sandybrown", - "seagreen", - "skyblue", - "slateblue", - "slategray", - "slategrey", - "springgreen", - "steelblue", - "whitesmoke", - "yellowgreen" - ], - "ignorePaths": [ - ".github/**", - "api/cpp/docs/conf.py", - "CHANGELOG.md", - "cspell.json", - "LICENSES", - "examples/*/lang/**", - "pnpm-lock.yaml", - "pnpm-workspace.yaml", - "REUSE.toml", - "**/Cargo.lock", - "docs/common/src/utils/slint.tmLanguage.json", - "ui-libraries/material/docs/vendor/**", - ".cspell/slint-project-words.txt", - ".cspell/slint-project-words-audit.tsv", - "tools/figma-inspector/tests/figma_output.json", - "**/*.gltf", - "**/*.po", - "**/*.pot", - "**/*.svg", - "target/**", - "**/node_modules/**" - ], - "overrides": [ - { - "filename": "demos/printerdemo/lang/fr/**", - "language": "en,fr", + "words": [ + "DSLINT", + "Espressif", + "libname", + "linebuffer", + "mylibrary", + "mywidgets", + "otherlibrary", + "Lmylibrary", + "progressindicator", + "standardbutton", + "standardlistview", + "standardtableview", + "rustup", + "setdefault", + "Sonoma", + "SUBDIR", + "Yocto", + "relpath", + "classslint", + "vectormodel", + "structslint", + "namespaceslint", + "compilerconfiguration", + "componentweakhandle", + "listmodel", + "skiarenderer", + "softwarerenderer", + "tschüß", + "TSCHÜSS", + "ὈΔΥΣΣΕΎΣ", + "ὀδυσσεύς", + "commonmark", + "strikethroughs", + "unlocalized" + ] + } + ], + "words": [ + "aarch", + "AARRGGBB", + "accesskit", + "antialiasing", + "Argb", + "armv", + "astrojs", + "Bezier", + "Bézier", + "cbindgen", + "cdylib", + "cmake", + "colspan", + "combobox", + "radiobutton", + "contexte", + "cupertino", + "datastructures", + "dealloc", + "distros", + "embedders", + "espflash", + "Femto", + "femtovg", + "flexboxlayout", + "flickable", + "focusable", + "frameless", + "fullscreen", + "gles", + "Goffart", + "gradians", + "grayscale", + "gridlayout", + "groupbox", + "Hausmann", + "Helvetica", + "imagefilter", + "inout", + "knip", + "layouting", + "linebreak", + "lineedit", + "LINUXFB", + "listview", + "lvalue", + "mdns", + "microcontroller", + "microcontrollers", + "MSVC", + "muda", + "napi", + "ogoffart", + "oneshot", + "Oooops", + "opengl", + "opengles", + "Pandoc", + "pico", + "pixmap", + "prestart", + "printerdemo", + "pythonw", + "replacen", + "rehype", + "Rgba", + "riscv", + "rowspan", + "RRGGBB", + "RRGGBBAA", + "rustc", + "rustdoc", + "rustflags", + "rvalue", + "SANDBOXING", + "scrollview", + "SDK", + "seti", + "sixtyfps", + "skia", + "slint", + "slintdoc", + "slintdocs", + "slintpad", + "spdx", + "spinbox", + "Srgb", + "streetsidesoftware", + "tableview", + "tabwidget", + "testcase", + "textedit", + "tmpobj", + "toolchain", + "toolkit", + "Toradex", + "touchpad", + "trackpad", + "trackpads", + "tronical", + "typeloader", + "uefi", + "uncompiled", + "Unshiftable", + "unerase", + "unmapping", + "unminimize", + "untracked", + "viewbox", + "virtualizes", + "Vivante", + "vtable", + "vulkan", + "wasm", + "webassembly", + "wgpu", + "windowrc", + "winit", + "xaarrggbb", + "Xcodegen", + "Xcodeproj", + "xtask", + "xtensa", + // CSS Color 4 named-color keywords not accepted by the default English dictionary (W3C CSS Color Module Level 4). + "aliceblue", + "antiquewhite", + "blanchedalmond", + "blueviolet", + "burlywood", + "cadetblue", + "cornflowerblue", + "cornsilk", + "darkcyan", + "darkgoldenrod", + "darkgray", + "darkgreen", + "darkgrey", + "darkkhaki", + "darkmagenta", + "darkolivegreen", + "darkorange", + "darkorchid", + "darkred", + "darksalmon", + "darkseagreen", + "darkslateblue", + "darkslategray", + "darkslategrey", + "darkturquoise", + "darkviolet", + "deeppink", + "deepskyblue", + "dimgray", + "dimgrey", + "dodgerblue", + "floralwhite", + "forestgreen", + "gainsboro", + "ghostwhite", + "greenyellow", + "hotpink", + "indianred", + "lavenderblush", + "lawngreen", + "lemonchiffon", + "lightcoral", + "lightcyan", + "lightgoldenrodyellow", + "lightgray", + "lightgreen", + "lightpink", + "lightsalmon", + "lightseagreen", + "lightskyblue", + "lightslategray", + "lightslategrey", + "lightsteelblue", + "lightyellow", + "limegreen", + "mediumaquamarine", + "mediumblue", + "mediumorchid", + "mediumpurple", + "mediumseagreen", + "mediumslateblue", + "mediumspringgreen", + "mediumturquoise", + "mediumvioletred", + "midnightblue", + "mintcream", + "mistyrose", + "navajowhite", + "oldlace", + "olivedrab", + "orangered", + "palegoldenrod", + "palegreen", + "paleturquoise", + "palevioletred", + "papayawhip", + "peachpuff", + "powderblue", + "rebeccapurple", + "rosybrown", + "royalblue", + "saddlebrown", + "sandybrown", + "seagreen", + "skyblue", + "slateblue", + "slategray", + "slategrey", + "springgreen", + "steelblue", + "whitesmoke", + "yellowgreen" + ], + "ignorePaths": [ + ".github/**", + "api/cpp/docs/conf.py", + "CHANGELOG.md", + "cspell.json", + "LICENSES", + "examples/*/lang/**", + "pnpm-lock.yaml", + "pnpm-workspace.yaml", + "REUSE.toml", + "**/Cargo.lock", + "docs/common/src/utils/slint.tmLanguage.json", + "ui-libraries/material/docs/vendor/**", + ".cspell/slint-project-words.txt", + ".cspell/slint-project-words-audit.tsv", + "tools/figma-inspector/tests/figma_output.json", + "**/*.gltf", + "**/*.po", + "**/*.pot", + "**/*.svg", + "target/**", + "**/node_modules/**" + ], + "overrides": [ + { + "filename": "demos/printerdemo/lang/fr/**", + "language": "en,fr", "dictionaries": [ "slint-project-words", "fr-fr-printerdemo" @@ -355,23 +358,23 @@ "nplurals", "YCMB" ] - }, - { - "filename": "**/*.rst", - "languageId": "restructuredtext" - }, - { - "filename": "**/*.slint", - "languageId": "rust" - } - ], - "dictionaryDefinitions": [ - { - "name": "slint-project-words", - "path": "./.cspell/slint-project-words.txt", - "addWords": true - } - ], + }, + { + "filename": "**/*.rst", + "languageId": "restructuredtext" + }, + { + "filename": "**/*.slint", + "languageId": "rust" + } + ], + "dictionaryDefinitions": [ + { + "name": "slint-project-words", + "path": "./.cspell/slint-project-words.txt", + "addWords": true + } + ], "dictionaries": [ "slint-project-words" ] diff --git a/docs/astro/src/content/docs/reference/primitive-types.mdx b/docs/astro/src/content/docs/reference/primitive-types.mdx index dccd007f674..40fc01c8bd2 100644 --- a/docs/astro/src/content/docs/reference/primitive-types.mdx +++ b/docs/astro/src/content/docs/reference/primitive-types.mdx @@ -186,6 +186,10 @@ export component FloatToString { In addition, call the in postfix style on any numeric value, for example `(-10).abs()` or `x.round()`. +#### to-string-unlocalized() -> string + +Returns a string representation of the number but not localized. This means the decimal separator will always be a dot. + ### int Signed integral number. @@ -478,6 +482,7 @@ export component Example { `int` and `float` convert implicitly to `string`. To control how many digits appear in the result, use the [`to-fixed()` and `to-precision()`](#to-fixeddigits-int---string) member functions instead of the implicit conversion. +To always use a dot as decimal separator regardless of the locale, use [`to-string-unlocalized()`](#to-string-unlocalized---string). For the other direction, convert a `string` to a number with the [`to-float()`](#to-float---float) member function, and check whether a string holds a valid number with `is-float()`. diff --git a/internal/compiler/builtins.slint b/internal/compiler/builtins.slint index b8d14349837..6954d5aa8fd 100644 --- a/internal/compiler/builtins.slint +++ b/internal/compiler/builtins.slint @@ -2375,6 +2375,9 @@ export component Path { //! //! A string providing the commands according to the SVG path specification. //! This property can only be set in a binding and cannot be accessed in an expression. + //! **Important:** if you concatenate strings with float values, use `.to-string-unlocalized()` + //! instead of implicit string conversion otherwise the path generation will not work on systems + //! with different localization. //! //! //! ## Path Using SVG Path Elements diff --git a/internal/compiler/expression_tree.rs b/internal/compiler/expression_tree.rs index eb547f90796..a698f0ab98a 100644 --- a/internal/compiler/expression_tree.rs +++ b/internal/compiler/expression_tree.rs @@ -46,6 +46,7 @@ pub enum BuiltinFunction { Exp, ToFixed, ToPrecision, + ToStringUnlocalized, SetFocusItem, ClearFocusItem, ShowPopupWindow, @@ -213,6 +214,7 @@ declare_builtin_function_types!( Exp: (Type::Float32) -> Type::Float32, ToFixed: (Type::Float32, Type::Int32) -> Type::String, ToPrecision: (Type::Float32, Type::Int32) -> Type::String, + ToStringUnlocalized: (Type::Float32) -> Type::String, SetFocusItem: (Type::ElementReference) -> Type::Void, ClearFocusItem: (Type::ElementReference) -> Type::Void, ShowPopupWindow: (Type::ElementReference) -> Type::Void, @@ -368,7 +370,8 @@ impl BuiltinFunction { | BuiltinFunction::Pow | BuiltinFunction::Exp | BuiltinFunction::ATan - | BuiltinFunction::ATan2 => true, + | BuiltinFunction::ATan2 + | BuiltinFunction::ToStringUnlocalized => true, // The result depends on the locale's decimal separator, like DecimalSeparator. // The constant propagation folds the locale-independent cases and promotes // their binding back to constant. @@ -468,7 +471,8 @@ impl BuiltinFunction { | BuiltinFunction::ATan | BuiltinFunction::ATan2 | BuiltinFunction::ToFixed - | BuiltinFunction::ToPrecision => true, + | BuiltinFunction::ToPrecision + | BuiltinFunction::ToStringUnlocalized => true, BuiltinFunction::SetFocusItem | BuiltinFunction::ClearFocusItem => false, BuiltinFunction::ShowPopupWindow | BuiltinFunction::ClosePopupWindow diff --git a/internal/compiler/generator/cpp.rs b/internal/compiler/generator/cpp.rs index d93faebca19..b363ccd25f7 100644 --- a/internal/compiler/generator/cpp.rs +++ b/internal/compiler/generator/cpp.rs @@ -4648,6 +4648,11 @@ fn compile_builtin_function_call( a.next().unwrap(), a.next().unwrap(), ) } + BuiltinFunction::ToStringUnlocalized => { + format!("[](double n) {{ slint::SharedString out; slint::cbindgen_private::slint_shared_string_from_number_unlocalized(&out, n); return out; }}({})", + a.next().unwrap(), + ) + } BuiltinFunction::SetFocusItem => { if let [llr::Expression::PropertyReference(pr)] = arguments { let window = access_window_field(ctx); diff --git a/internal/compiler/generator/rust.rs b/internal/compiler/generator/rust.rs index c7127c70f84..360829b8159 100644 --- a/internal/compiler/generator/rust.rs +++ b/internal/compiler/generator/rust.rs @@ -4056,6 +4056,10 @@ fn compile_builtin_function_call( let (a1, a2) = (a.next().unwrap(), a.next().unwrap()); quote!(sp::shared_string_from_number_precision(#a1 as f64, (#a2 as i32).max(0) as usize)) } + BuiltinFunction::ToStringUnlocalized => { + let a1 = a.next().unwrap(); + quote!(sp::shared_string_from_number_unlocalized(#a1 as f64)) + } BuiltinFunction::StringToFloat => { quote!(sp::string_to_float(#(#a)*.as_str()).unwrap_or_default()) } diff --git a/internal/compiler/llr/optim_passes/inline_expressions.rs b/internal/compiler/llr/optim_passes/inline_expressions.rs index 2a018914fa4..f733831997d 100644 --- a/internal/compiler/llr/optim_passes/inline_expressions.rs +++ b/internal/compiler/llr/optim_passes/inline_expressions.rs @@ -115,6 +115,7 @@ fn builtin_function_cost(function: &BuiltinFunction) -> isize { BuiltinFunction::Exp => 10, BuiltinFunction::ToFixed => ALLOC_COST, BuiltinFunction::ToPrecision => ALLOC_COST, + BuiltinFunction::ToStringUnlocalized => ALLOC_COST, BuiltinFunction::SetFocusItem | BuiltinFunction::ClearFocusItem => isize::MAX, BuiltinFunction::ShowPopupWindow | BuiltinFunction::ClosePopupWindow diff --git a/internal/compiler/lookup.rs b/internal/compiler/lookup.rs index 573eb1e9a47..3fd5300ef7b 100644 --- a/internal/compiler/lookup.rs +++ b/internal/compiler/lookup.rs @@ -1163,6 +1163,9 @@ impl LookupObject for NumberExpression<'_> { .or_else(|| f2("sign", member_macro(BuiltinMacroFunction::Sign))) .or_else(|| f2("to-fixed", member_function(BuiltinFunction::ToFixed))) .or_else(|| f2("to-precision", member_function(BuiltinFunction::ToPrecision))) + .or_else(|| { + f2("to-string-unlocalized", member_function(BuiltinFunction::ToStringUnlocalized)) + }) .or_else(|| NumberWithUnitExpression(self.0).for_each_entry(ctx, f)) } } diff --git a/internal/core/string.rs b/internal/core/string.rs index 32bd85122a6..01f7aaad234 100644 --- a/internal/core/string.rs +++ b/internal/core/string.rs @@ -341,10 +341,16 @@ where } } +/// Convert a f64 to a SharedString but unlocalized with "." as decimal separator +#[inline] +pub fn shared_string_from_number_unlocalized(n: f64) -> SharedString { + crate::format!("{}", i_slint_common::FormattedNumber(n)) +} + /// Convert a f64 to a SharedString pub fn shared_string_from_number(n: f64) -> SharedString { crate::context::GLOBAL_CONTEXT.with(|ctx| { - let mut result = crate::format!("{}", i_slint_common::FormattedNumber(n)); + let mut result = shared_string_from_number_unlocalized(n); if let Some(ctx) = ctx.get() { let pinned = ctx.0.as_ref().project_ref(); @@ -542,6 +548,17 @@ pub(crate) mod ffi { } } + /// Create a string from a number but unlocalized. + /// The resulting structure must be passed to slint_shared_string_drop + #[unsafe(no_mangle)] + pub unsafe extern "C" fn slint_shared_string_from_number_unlocalized( + out: *mut SharedString, + n: f64, + ) { + let str = shared_string_from_number_unlocalized(n); + unsafe { core::ptr::write(out, str) }; + } + /// Create a string from a number. /// The resulting structure must be passed to slint_shared_string_drop #[unsafe(no_mangle)] diff --git a/internal/interpreter/eval.rs b/internal/interpreter/eval.rs index 7f1356a1e67..1fc0c3750e4 100644 --- a/internal/interpreter/eval.rs +++ b/internal/interpreter/eval.rs @@ -861,6 +861,10 @@ fn call_builtin_function( let precision: usize = precision.max(0) as usize; Value::String(i_slint_core::string::shared_string_from_number_precision(n, precision)) } + BuiltinFunction::ToStringUnlocalized => { + let n: f64 = eval_expression(&arguments[0], local_context).try_into().unwrap(); + Value::String(i_slint_core::string::shared_string_from_number_unlocalized(n)) + } BuiltinFunction::SetFocusItem => { if arguments.len() != 1 { panic!("internal error: incorrect argument count to SetFocusItem") diff --git a/tests/cases/translations/decimal_separator.slint b/tests/cases/translations/decimal_separator.slint index f966574ac84..73ff91e2184 100644 --- a/tests/cases/translations/decimal_separator.slint +++ b/tests/cases/translations/decimal_separator.slint @@ -15,6 +15,8 @@ export component TestCase { in-out property string_as_float: value_string.to-float(); in-out property is_float: value_string.is-float(); + in-out property float_as_string_unlocalized: value.to-string-unlocalized(); + // \{ cannot be in a slint macro, so we add it here, because we wanna execute the Test with // compiled source (otherwise bundling translations is not possible) out property same_or_diff: "\{the-decimal-separator}"; @@ -41,6 +43,7 @@ assert!(slint::select_bundled_translation("fr").is_ok()); assert_eq!(instance.get_the_decimal_separator(), ","); instance.set_value(-5.5); assert_eq!(instance.get_float_as_string(), "-5,5"); +assert_eq!(instance.get_float_as_string_unlocalized(), "-5.5"); assert_eq!(instance.get_const_float_as_string(), "1,5"); assert_eq!(instance.get_const_int_as_string(), "42"); assert_eq!(instance.get_const_to_fixed(), "1,50"); @@ -57,6 +60,7 @@ assert!(slint::select_bundled_translation("en").is_ok()); assert_eq!(instance.get_the_decimal_separator(), "."); instance.set_value(7.123); assert_eq!(instance.get_float_as_string(), "7.123"); +assert_eq!(instance.get_float_as_string_unlocalized(), "7.123"); assert_eq!(instance.get_const_float_as_string(), "1.5"); assert_eq!(instance.get_const_to_fixed(), "1.50"); assert_eq!(instance.get_const_is_float(), false); @@ -85,6 +89,7 @@ assert(slint::select_bundled_translation("fr")); assert_eq(instance.get_the_decimal_separator(), ","); instance.set_value(-5.5); assert_eq(instance.get_float_as_string(), "-5,5"); +assert_eq(instance.get_float_as_string_unlocalized(), "-5.5"); assert_eq(instance.get_const_float_as_string(), "1,5"); assert_eq(instance.get_const_int_as_string(), "42"); assert_eq(instance.get_const_to_fixed(), "1,50"); @@ -101,6 +106,7 @@ assert(slint::select_bundled_translation("en")); assert_eq(instance.get_the_decimal_separator(), "."); instance.set_value(7.123); assert_eq(instance.get_float_as_string(), "7.123"); +assert_eq(instance.get_float_as_string_unlocalized(), "7.123"); assert_eq(instance.get_const_float_as_string(), "1.5"); assert_eq(instance.get_const_to_fixed(), "1.50"); assert_eq(instance.get_const_is_float(), false); @@ -113,4 +119,4 @@ instance.set_value_string("3.2"); assert_eq(instance.get_is_float(), true); assert_eq(instance.get_string_as_float(), 3.2); ``` -*/ \ No newline at end of file +*/ diff --git a/tools/lsp/preview/eval.rs b/tools/lsp/preview/eval.rs index 564d8e60498..62f5d34ca92 100644 --- a/tools/lsp/preview/eval.rs +++ b/tools/lsp/preview/eval.rs @@ -437,6 +437,11 @@ fn handle_builtin_function( let precision: usize = precision.max(0) as usize; Value::String(i_slint_core::string::shared_string_from_number_precision(n, precision)) } + BuiltinFunction::ToStringUnlocalized => { + let n: f64 = + eval_expression(&arguments[0], local_context, None).try_into().unwrap_or_default(); + Value::String(i_slint_core::string::shared_string_from_number_unlocalized(n)) + } BuiltinFunction::StringIsFloat => { if arguments.len() != 1 { return Value::Void;