mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-04 10:50:00 +00:00
WIP: start working on translations: @tr()
This commit just do the parsing of the @tr macro.
This commit is contained in:
parent
3a4f3c61d5
commit
dcd8450dfa
17 changed files with 161 additions and 52 deletions
|
@ -11,13 +11,13 @@ export { TableViewPageAdapter }
|
|||
component App inherits Window {
|
||||
preferred-width: 700px;
|
||||
preferred-height: 500px;
|
||||
title: "Slint Widgets Gallery";
|
||||
title: @tr("Slint Widgets Gallery");
|
||||
icon: @image-url("../../logo/slint-logo-small-light-128x128.png");
|
||||
|
||||
HorizontalLayout {
|
||||
side-bar := SideBar {
|
||||
title: "Slint Widgets Gallery";
|
||||
model: ["Controls", "ListView", "TableView", "TextEdit", "About"];
|
||||
title: @tr("Slint Widgets Gallery");
|
||||
model: [@tr("Controls"), @tr("ListView"), @tr("TableView"), @tr("TextEdit"), @tr("About")];
|
||||
}
|
||||
|
||||
if(side-bar.current-item == 0) : ControlsPage {}
|
||||
|
|
|
@ -7,38 +7,38 @@ import { GallerySettings } from "../gallery_settings.slint";
|
|||
import { Page } from "page.slint";
|
||||
|
||||
export component ControlsPage inherits Page {
|
||||
title: "Controls";
|
||||
description: "This page gives an overview of the default widget set provided by Slint. The widgets are available in different styles native, fluent-(dark/light) and material-(dark/light). The widgets can be imported from \"std-widgets.slint\".";
|
||||
title: @tr("Controls");
|
||||
description: @tr("This page gives an overview of the default widget set provided by Slint. The widgets are available in different styles native, fluent-(dark/light) and material-(dark/light). The widgets can be imported from \"std-widgets.slint\".");
|
||||
|
||||
GroupBox {
|
||||
vertical-stretch: 0;
|
||||
title: "Buttons";
|
||||
title: @tr("Buttons");
|
||||
|
||||
HorizontalBox {
|
||||
alignment: start;
|
||||
padding: 0px;
|
||||
|
||||
Button {
|
||||
text: "Regular Button";
|
||||
text: @tr("Regular Button");
|
||||
enabled: GallerySettings.widgets-enabled;
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Button with Icon";
|
||||
text: @tr("Button with Icon");
|
||||
icon: @image-url("../../thumbsup.png");
|
||||
enabled: GallerySettings.widgets-enabled;
|
||||
}
|
||||
|
||||
Button {
|
||||
checkable: true;
|
||||
text: self.checked ? "ON" : "OFF";
|
||||
text: self.checked ? @tr("ON") : @tr("OFF");
|
||||
enabled: GallerySettings.widgets-enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GroupBox {
|
||||
title: "CheckBox - SpinBox - ComboBox - Switch";
|
||||
title: @tr("CheckBox - SpinBox - ComboBox - Switch");
|
||||
vertical-stretch: 0;
|
||||
|
||||
HorizontalBox {
|
||||
|
@ -46,7 +46,7 @@ export component ControlsPage inherits Page {
|
|||
padding: 0px;
|
||||
|
||||
checkbox := CheckBox {
|
||||
text: checkbox.checked ? "(checked)" : "(unchecked)";
|
||||
text: checkbox.checked ? @tr("(checked)") : @tr("(unchecked)");
|
||||
checked: true;
|
||||
enabled: GallerySettings.widgets-enabled;
|
||||
}
|
||||
|
@ -58,12 +58,12 @@ export component ControlsPage inherits Page {
|
|||
}
|
||||
|
||||
ComboBox {
|
||||
model: ["Select Something", "From this", "Combobox"];
|
||||
model: [@tr("Select Something"), @tr("From this"), @tr("Combobox")];
|
||||
enabled: GallerySettings.widgets-enabled;
|
||||
}
|
||||
|
||||
Switch {
|
||||
text: "Flight Mode";
|
||||
text: @tr("Flight Mode");
|
||||
checked: true;
|
||||
enabled: GallerySettings.widgets-enabled;
|
||||
}
|
||||
|
@ -71,17 +71,17 @@ export component ControlsPage inherits Page {
|
|||
}
|
||||
|
||||
GroupBox {
|
||||
title: "LineEdit";
|
||||
title: @tr("LineEdit");
|
||||
vertical-stretch: 0;
|
||||
|
||||
LineEdit {
|
||||
placeholder-text: "Enter some text";
|
||||
placeholder-text: @tr("Enter some text");
|
||||
enabled: GallerySettings.widgets-enabled;
|
||||
}
|
||||
}
|
||||
|
||||
GroupBox {
|
||||
title: "Slider";
|
||||
title: @tr("Slider");
|
||||
vertical-stretch: 0;
|
||||
|
||||
i-slider := Slider {
|
||||
|
@ -94,7 +94,7 @@ export component ControlsPage inherits Page {
|
|||
}
|
||||
|
||||
GroupBox {
|
||||
title: "ProgressIndicator";
|
||||
title: @tr("ProgressIndicator");
|
||||
vertical-stretch: 0;
|
||||
|
||||
VerticalLayout {
|
||||
|
@ -108,30 +108,30 @@ export component ControlsPage inherits Page {
|
|||
}
|
||||
|
||||
CheckBox {
|
||||
text: "indeterminate";
|
||||
text: @tr("indeterminate");
|
||||
checked <=> i-progress-indicator.indeterminate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GroupBox {
|
||||
title: "TabWidget";
|
||||
title: @tr("TabWidget");
|
||||
|
||||
TabWidget {
|
||||
Tab {
|
||||
title: "Tab 1";
|
||||
title: @tr("Tab 1");
|
||||
|
||||
VerticalBox {
|
||||
alignment: start;
|
||||
|
||||
GroupBox {
|
||||
title: "Content of tab 1";
|
||||
title: @tr("Content of tab 1");
|
||||
|
||||
HorizontalBox {
|
||||
alignment: start;
|
||||
|
||||
Button {
|
||||
text: "Click me";
|
||||
text: @tr("Click me");
|
||||
enabled: GallerySettings.widgets-enabled;
|
||||
}
|
||||
}
|
||||
|
@ -140,19 +140,19 @@ export component ControlsPage inherits Page {
|
|||
}
|
||||
|
||||
Tab {
|
||||
title: "Tab 2";
|
||||
title: @tr("Tab 2");
|
||||
|
||||
VerticalBox {
|
||||
alignment: start;
|
||||
|
||||
GroupBox {
|
||||
title: "Content of tab 2";
|
||||
title: @tr("Content of tab 2");
|
||||
|
||||
VerticalBox {
|
||||
alignment: start;
|
||||
|
||||
CheckBox {
|
||||
text: "Check me";
|
||||
text: @tr("Check me");
|
||||
enabled: GallerySettings.widgets-enabled;
|
||||
}
|
||||
}
|
||||
|
@ -161,11 +161,11 @@ export component ControlsPage inherits Page {
|
|||
}
|
||||
|
||||
Tab {
|
||||
title: "Tab 3";
|
||||
title: @tr("Tab 3");
|
||||
|
||||
VerticalBox {
|
||||
Text {
|
||||
text: "Content of tab 3";
|
||||
text: @tr("Content of tab 3");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ import { GallerySettings } from "../gallery_settings.slint";
|
|||
import { Page } from "page.slint";
|
||||
|
||||
export component ListViewPage inherits Page {
|
||||
title: "ListView";
|
||||
description: "ListViews can be used to display a list of elements. The StandardListBox is like the default ListView just with a default text based definition of the visual items. Both can be imported from \"std-widgets.slint\"";
|
||||
title: @tr("ListView");
|
||||
description: @tr("ListViews can be used to display a list of elements. The StandardListBox is like the default ListView just with a default text based definition of the visual items. Both can be imported from \"std-widgets.slint\"");
|
||||
|
||||
HorizontalBox {
|
||||
vertical-stretch: 1;
|
||||
|
@ -22,7 +22,7 @@ export component ListViewPage inherits Page {
|
|||
source: @image-url("../../thumbsup.png");
|
||||
}
|
||||
Text {
|
||||
text: "Item " + i;
|
||||
text: @tr("Item {}", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,13 +34,13 @@ export component ListViewPage inherits Page {
|
|||
|
||||
StandardListView {
|
||||
model: [
|
||||
{text: "Lorem"}, {text: "ipsum"},{text: "dolor"},{text: "sit"},{text: "amet"},{text: "consetetur"},
|
||||
{text: "Lorem"}, {text: "ipsum"},{text: "dolor"},{text: "sit"},{text: "amet"},{text: "consetetur"},
|
||||
{text: "Lorem"}, {text: "ipsum"},{text: "dolor"},{text: "sit"},{text: "amet"},{text: "consetetur"},
|
||||
{text: "Lorem"}, {text: "ipsum"},{text: "dolor"},{text: "sit"},{text: "amet"},{text: "consetetur"},
|
||||
{text: "Lorem"}, {text: "ipsum"},{text: "dolor"},{text: "sit"},{text: "amet"},{text: "consetetur"},
|
||||
{text: "Lorem"}, {text: "ipsum"},{text: "dolor"},{text: "sit"},{text: "amet"},{text: "consetetur"},
|
||||
{text: "Lorem"}, {text: "ipsum"},{text: "dolor"},{text: "sit"},{text: "amet"},{text: "consetetur"},
|
||||
{text: @tr("Lorem")}, {text: @tr("ipsum")},{text: @tr("dolor")},{text: @tr("sit")},{text: @tr("amet")},{text: @tr("consetetur")},
|
||||
{text: @tr("Lorem")}, {text: @tr("ipsum")},{text: @tr("dolor")},{text: @tr("sit")},{text: @tr("amet")},{text: @tr("consetetur")},
|
||||
{text: @tr("Lorem")}, {text: @tr("ipsum")},{text: @tr("dolor")},{text: @tr("sit")},{text: @tr("amet")},{text: @tr("consetetur")},
|
||||
{text: @tr("Lorem")}, {text: @tr("ipsum")},{text: @tr("dolor")},{text: @tr("sit")},{text: @tr("amet")},{text: @tr("consetetur")},
|
||||
{text: @tr("Lorem")}, {text: @tr("ipsum")},{text: @tr("dolor")},{text: @tr("sit")},{text: @tr("amet")},{text: @tr("consetetur")},
|
||||
{text: @tr("Lorem")}, {text: @tr("ipsum")},{text: @tr("dolor")},{text: @tr("sit")},{text: @tr("amet")},{text: @tr("consetetur")},
|
||||
{text: @tr("Lorem")}, {text: @tr("ipsum")},{text: @tr("dolor")},{text: @tr("sit")},{text: @tr("amet")},{text: @tr("consetetur")},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ export component Page inherits VerticalBox {
|
|||
|
||||
Switch {
|
||||
horizontal-stretch: 0;
|
||||
text: "Widgets enabled";
|
||||
text: @tr("Widgets enabled");
|
||||
checked <=> GallerySettings.widgets-enabled;
|
||||
enabled: true;
|
||||
}
|
||||
|
|
|
@ -19,14 +19,14 @@ export global TableViewPageAdapter {
|
|||
}
|
||||
|
||||
export component TableViewPage inherits Page {
|
||||
title: "TableView";
|
||||
description: "StandardTableView can be used to display a list of text elements in columns and rows. It can be imported from \"std-widgets.slint\"";
|
||||
title: @tr("TableView");
|
||||
description: @tr("StandardTableView can be used to display a list of text elements in columns and rows. It can be imported from \"std-widgets.slint\"");
|
||||
|
||||
HorizontalBox {
|
||||
vertical-stretch: 1;
|
||||
|
||||
GroupBox {
|
||||
title: "StandardTableView";
|
||||
title: @tr("StandardTableView");
|
||||
vertical-stretch: 0;
|
||||
|
||||
StandardTableView {
|
||||
|
@ -39,10 +39,10 @@ export component TableViewPage inherits Page {
|
|||
}
|
||||
|
||||
columns: [
|
||||
{ title: "Header 1" },
|
||||
{ title: "Header 2" },
|
||||
{ title: "Header 3" },
|
||||
{ title: "Header 4" },
|
||||
{ title: @tr("Header 1") },
|
||||
{ title: @tr("Header 2") },
|
||||
{ title: @tr("Header 3") },
|
||||
{ title: @tr("Header 4") },
|
||||
];
|
||||
rows: TableViewPageAdapter.row_data;
|
||||
}
|
||||
|
|
|
@ -6,23 +6,23 @@ import { GallerySettings } from "../gallery_settings.slint";
|
|||
import { Page } from "page.slint";
|
||||
|
||||
export component TextEditPage inherits Page {
|
||||
title: "TextEdit";
|
||||
description: "Similar to LineEdit, but can be used to enter several lines of text. The widget can be imported from \"std-widgets.slint\".";
|
||||
title: @tr("TextEdit");
|
||||
description: @tr("Similar to LineEdit, but can be used to enter several lines of text. The widget can be imported from \"std-widgets.slint\".");
|
||||
|
||||
HorizontalBox {
|
||||
GroupBox {
|
||||
vertical-stretch: 0;
|
||||
title: "Word-Wrap";
|
||||
title: @tr("Word-Wrap");
|
||||
te1 := TextEdit {
|
||||
// min-width: 200px;
|
||||
text: "This is our TextEdit widget, which allows for editing text that spans over multiple paragraphs.\nFor example this line starts in a new paragraph.\n\nWhen the amount of lines - due to wrapping and number of paragraphs - exceeds the available vertical height, a vertical scrollbar is shown that allows scrolling.\nYou may want to enter a bit of text here then in order to make them visible.";
|
||||
text: @tr("This is our TextEdit widget, which allows for editing text that spans over multiple paragraphs.\nFor example this line starts in a new paragraph.\n\nWhen the amount of lines - due to wrapping and number of paragraphs - exceeds the available vertical height, a vertical scrollbar is shown that allows scrolling.\nYou may want to enter a bit of text here then in order to make them visible.");
|
||||
wrap: word-wrap;
|
||||
enabled: GallerySettings.widgets-enabled;
|
||||
}
|
||||
}
|
||||
|
||||
GroupBox {
|
||||
title: "No-Wrap";
|
||||
title: @tr("No-Wrap");
|
||||
vertical-stretch: 0;
|
||||
te2 := TextEdit {
|
||||
// min-width: 200px;
|
||||
|
|
|
@ -61,6 +61,7 @@ pub enum BuiltinFunction {
|
|||
RegisterCustomFontByPath,
|
||||
RegisterCustomFontByMemory,
|
||||
RegisterBitmapFont,
|
||||
Translate,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -202,6 +203,10 @@ impl BuiltinFunction {
|
|||
BuiltinFunction::RegisterBitmapFont => {
|
||||
Type::Function { return_type: Box::new(Type::Void), args: vec![Type::Int32] }
|
||||
}
|
||||
BuiltinFunction::Translate => Type::Function {
|
||||
return_type: Box::new(Type::String),
|
||||
args: vec![Type::String, Type::Array(Type::String.into())],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,6 +258,7 @@ impl BuiltinFunction {
|
|||
BuiltinFunction::RegisterCustomFontByPath
|
||||
| BuiltinFunction::RegisterCustomFontByMemory
|
||||
| BuiltinFunction::RegisterBitmapFont => false,
|
||||
BuiltinFunction::Translate => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,6 +303,7 @@ impl BuiltinFunction {
|
|||
BuiltinFunction::RegisterCustomFontByPath
|
||||
| BuiltinFunction::RegisterCustomFontByMemory
|
||||
| BuiltinFunction::RegisterBitmapFont => false,
|
||||
BuiltinFunction::Translate => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2833,6 +2833,9 @@ fn compile_builtin_function_call(
|
|||
panic!("internal error: invalid args to ImplicitLayoutInfo {:?}", arguments)
|
||||
}
|
||||
}
|
||||
BuiltinFunction::Translate => {
|
||||
format!("slint::private_api::translate({});", a.join(","))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2441,6 +2441,9 @@ fn compile_builtin_function_call(
|
|||
let window_adapter_tokens = access_window_adapter_field(ctx);
|
||||
quote!(slint::private_unstable_api::re_exports::WindowInner::from_pub(#window_adapter_tokens.window()).set_text_input_focused(#(#a)*))
|
||||
}
|
||||
BuiltinFunction::Translate => {
|
||||
todo!("BuiltinFunction::Translate in rust")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -106,6 +106,7 @@ fn builtin_function_cost(function: &BuiltinFunction) -> isize {
|
|||
BuiltinFunction::DarkColorScheme => isize::MAX,
|
||||
BuiltinFunction::SetTextInputFocused => PROPERTY_ACCESS_COST,
|
||||
BuiltinFunction::TextInputFocused => PROPERTY_ACCESS_COST,
|
||||
BuiltinFunction::Translate => 2 * ALLOC_COST + PROPERTY_ACCESS_COST,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -359,7 +359,7 @@ declare_syntax! {
|
|||
// FIXME: the test should test that as alternative rather than several of them (but it can also be a literal)
|
||||
Expression-> [ ?Expression, ?FunctionCallExpression, ?IndexExpression, ?SelfAssignment,
|
||||
?ConditionalExpression, ?QualifiedName, ?BinaryExpression, ?Array, ?ObjectLiteral,
|
||||
?UnaryOpExpression, ?CodeBlock, ?StringTemplate, ?AtImageUrl, ?AtGradient,
|
||||
?UnaryOpExpression, ?CodeBlock, ?StringTemplate, ?AtImageUrl, ?AtGradient, ?AtTr,
|
||||
?MemberAccess ],
|
||||
/// Concatenate the Expressions to make a string (usually expended from a template string)
|
||||
StringTemplate -> [*Expression],
|
||||
|
@ -367,6 +367,8 @@ declare_syntax! {
|
|||
AtImageUrl -> [],
|
||||
/// `@linear-gradient(...)` or `@radial-gradient(...)`
|
||||
AtGradient -> [*Expression],
|
||||
/// `@tr("foo", ...)` // the string is a StringLiteral
|
||||
AtTr -> [*Expression],
|
||||
/// expression()
|
||||
FunctionCallExpression -> [*Expression],
|
||||
/// `expression[index]`
|
||||
|
|
|
@ -212,6 +212,7 @@ fn parse_expression_helper(p: &mut impl Parser, precedence: OperatorPrecedence)
|
|||
/// ```test
|
||||
/// @image-url("/foo/bar.png")
|
||||
/// @linear-gradient(0deg, blue, red)
|
||||
/// @tr("foo", bar)
|
||||
/// ```
|
||||
fn parse_at_keyword(p: &mut impl Parser) {
|
||||
debug_assert_eq!(p.peek().kind(), SyntaxKind::At);
|
||||
|
@ -230,10 +231,13 @@ fn parse_at_keyword(p: &mut impl Parser) {
|
|||
"radial-gradient" | "radial_gradient" => {
|
||||
parse_gradient(p);
|
||||
}
|
||||
"tr" => {
|
||||
parse_tr(p);
|
||||
}
|
||||
_ => {
|
||||
p.consume();
|
||||
p.test(SyntaxKind::Identifier); // consume the identifier, so that autocomplete works
|
||||
p.error("Expected 'image-url', 'linear-gradient' or 'radial-gradient' after '@'");
|
||||
p.error("Expected 'image-url', 'tr', 'linear-gradient' or 'radial-gradient' after '@'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -351,3 +355,33 @@ fn parse_gradient(p: &mut impl Parser) {
|
|||
p.test(SyntaxKind::Comma);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(test, parser_test)]
|
||||
/// ```test,AtTr
|
||||
/// @tr("foo")
|
||||
/// @tr("foo", bar)
|
||||
/// ```
|
||||
fn parse_tr(p: &mut impl Parser) {
|
||||
let mut p = p.start_node(SyntaxKind::AtTr);
|
||||
p.expect(SyntaxKind::At);
|
||||
debug_assert_eq!(p.peek().as_str(), "tr");
|
||||
p.expect(SyntaxKind::Identifier); //"tr"
|
||||
p.expect(SyntaxKind::LParent);
|
||||
let peek = p.peek();
|
||||
|
||||
if peek.kind() != SyntaxKind::StringLiteral
|
||||
|| !peek.as_str().starts_with('"')
|
||||
|| !peek.as_str().ends_with('"')
|
||||
{
|
||||
p.error("Expected plain string literal");
|
||||
return;
|
||||
}
|
||||
p.expect(SyntaxKind::StringLiteral);
|
||||
|
||||
while p.test(SyntaxKind::Comma) {
|
||||
if !parse_expression(&mut *p) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
p.expect(SyntaxKind::RParent);
|
||||
}
|
||||
|
|
|
@ -241,6 +241,7 @@ impl Expression {
|
|||
.map(|n| Self::from_expression_node(n, ctx))
|
||||
.or_else(|| node.AtImageUrl().map(|n| Self::from_at_image_url_node(n, ctx)))
|
||||
.or_else(|| node.AtGradient().map(|n| Self::from_at_gradient(n, ctx)))
|
||||
.or_else(|| node.AtTr().map(|n| Self::from_at_tr(n, ctx)))
|
||||
.or_else(|| {
|
||||
node.QualifiedName().map(|n| {
|
||||
let exp =
|
||||
|
@ -515,6 +516,36 @@ impl Expression {
|
|||
}
|
||||
}
|
||||
|
||||
fn from_at_tr(node: syntax_nodes::AtTr, ctx: &mut LookupCtx) -> Expression {
|
||||
let Some(string) = node
|
||||
.child_text(SyntaxKind::StringLiteral)
|
||||
.and_then(|s| crate::literals::unescape_string(&s))
|
||||
else {
|
||||
ctx.diag.push_error("Cannot parse string literal".into(), &node);
|
||||
return Expression::Invalid;
|
||||
};
|
||||
|
||||
let subs = node.Expression().map(|n| {
|
||||
Expression::from_expression_node(n.clone(), ctx).maybe_convert_to(
|
||||
Type::String,
|
||||
&n,
|
||||
ctx.diag,
|
||||
)
|
||||
});
|
||||
|
||||
Expression::FunctionCall {
|
||||
function: Box::new(Expression::BuiltinFunctionReference(
|
||||
BuiltinFunction::Translate,
|
||||
Some(node.to_source_location()),
|
||||
)),
|
||||
arguments: vec![
|
||||
Expression::StringLiteral(string),
|
||||
Expression::Array { element_ty: Type::String, values: subs.collect() },
|
||||
],
|
||||
source_location: Some(node.to_source_location()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform the lookup
|
||||
fn from_qualified_name_node(
|
||||
node: syntax_nodes::QualifiedName,
|
||||
|
|
23
internal/compiler/tests/syntax/basic/tr.slint
Normal file
23
internal/compiler/tests/syntax/basic/tr.slint
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||
|
||||
export component X {
|
||||
property <string> t1: @tr(boo);
|
||||
// ^error{Expected plain string literal}
|
||||
// ^^error{Syntax error: expected ';'}
|
||||
// ^^^error{Parse error}
|
||||
property <string> t2: @tr("boo\{t1}oo");
|
||||
// ^error{Expected plain string literal}
|
||||
// ^^error{Syntax error: expected ';'}
|
||||
|
||||
property <string> t3: @tr("boo" + "foo");
|
||||
// ^error{Syntax error: expected '\)'}
|
||||
// ^^error{Syntax error: expected ';'}
|
||||
|
||||
property <string> t4: @tr("foo{}", t1);
|
||||
|
||||
property <string> t4: @tr("foo{}", t1 t2);
|
||||
// ^error{Syntax error: expected '\)'}
|
||||
// ^^error{Syntax error: expected ';'}
|
||||
|
||||
}
|
|
@ -867,6 +867,9 @@ fn call_builtin_function(
|
|||
BuiltinFunction::RegisterCustomFontByMemory | BuiltinFunction::RegisterBitmapFont => {
|
||||
unimplemented!()
|
||||
}
|
||||
BuiltinFunction::Translate => {
|
||||
todo!("translate in the interpeter");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -202,6 +202,7 @@ pub(crate) fn completion_at(
|
|||
{
|
||||
return Some(
|
||||
[
|
||||
("tr", "tr(\"$1\")"),
|
||||
("image-url", "image-url(\"$1\")"),
|
||||
("linear-gradient", "linear-gradient($1)"),
|
||||
("radial-gradient", "radial-gradient(circle, $1)"),
|
||||
|
|
|
@ -96,6 +96,7 @@ pub fn get_semantic_tokens(
|
|||
SyntaxKind::ReturnStatement => Some((self::KEYWORD, 0)),
|
||||
SyntaxKind::AtImageUrl => Some((self::MACRO, 0)),
|
||||
SyntaxKind::AtGradient => Some((self::MACRO, 0)),
|
||||
SyntaxKind::AtTr => Some((self::MACRO, 0)),
|
||||
SyntaxKind::ConditionalExpression => Some((self::KEYWORD, 0)),
|
||||
SyntaxKind::ObjectMember => Some((self::PROPERTY, 1 << self::DECLARATION)),
|
||||
SyntaxKind::States => Some((self::KEYWORD, 0)),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue