if *changed != props.color {
diff --git a/rust/perspective-viewer/src/rust/components/form/optional_field.rs b/rust/perspective-viewer/src/rust/components/form/optional_field.rs
index 2971039ffa..01fb512582 100644
--- a/rust/perspective-viewer/src/rust/components/form/optional_field.rs
+++ b/rust/perspective-viewer/src/rust/components/form/optional_field.rs
@@ -30,7 +30,7 @@ pub struct OptionalFieldProps {
pub fn optional_field(props: &OptionalFieldProps) -> Html {
html! {
<>
-
+
@@ -39,12 +39,12 @@ pub fn optional_field(props: &OptionalFieldProps) -> Html {
} else {
}
diff --git a/rust/perspective-viewer/src/rust/components/number_column_style.rs b/rust/perspective-viewer/src/rust/components/number_column_style.rs
index 88cffa1ef0..c0869c0c8e 100644
--- a/rust/perspective-viewer/src/rust/components/number_column_style.rs
+++ b/rust/perspective-viewer/src/rust/components/number_column_style.rs
@@ -328,13 +328,13 @@ impl Component for NumberColumnStyle {
- label="Foreground"
+ label="foreground"
on_change={fg_mode_changed}
current_value={self.fg_mode}
/>
{ fg_controls }
- label="Background"
+ label="background"
on_change={bg_mode_changed}
current_value={self.bg_mode}
/>
@@ -432,7 +432,7 @@ impl NumberColumnStyle {
props!(NumberFieldProps {
default: value,
current_value: value,
- label: "Max Value",
+ label: "max-value",
on_change
})
}
diff --git a/rust/perspective-viewer/src/rust/components/plugin_selector.rs b/rust/perspective-viewer/src/rust/components/plugin_selector.rs
index e025fdf3bd..8545508ec6 100644
--- a/rust/perspective-viewer/src/rust/components/plugin_selector.rs
+++ b/rust/perspective-viewer/src/rust/components/plugin_selector.rs
@@ -158,13 +158,26 @@ struct PluginSelectProps {
#[function_component]
fn PluginSelect(props: &PluginSelectProps) -> Html {
let name = props.name.clone().tee::<2>();
+ let path: String = props
+ .name
+ .chars()
+ .map(|x| {
+ if x.is_alphanumeric() {
+ x.to_ascii_lowercase()
+ } else {
+ '-'
+ }
+ })
+ .collect();
+
html! {
- { &props.name }
+
}
}
diff --git a/rust/perspective-viewer/src/rust/components/status_bar.rs b/rust/perspective-viewer/src/rust/components/status_bar.rs
index b1b1b7eec8..0f5172be05 100644
--- a/rust/perspective-viewer/src/rust/components/status_bar.rs
+++ b/rust/perspective-viewer/src/rust/components/status_bar.rs
@@ -246,29 +246,28 @@ impl Component for StatusBar {
data-value={ctx.props().presentation.get_title().unwrap_or_default()}
>
+
diff --git a/rust/perspective-viewer/src/rust/components/status_bar_counter.rs b/rust/perspective-viewer/src/rust/components/status_bar_counter.rs
index f22554d2fe..515858aca9 100644
--- a/rust/perspective-viewer/src/rust/components/status_bar_counter.rs
+++ b/rust/perspective-viewer/src/rust/components/status_bar_counter.rs
@@ -10,7 +10,6 @@
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
-use num_format::{Locale, ToFormattedString};
use yew::prelude::*;
use crate::session::ViewStats;
@@ -33,6 +32,8 @@ impl PartialEq for StatusBarRowsCounterProps {
}
}
+use crate::utils::ToFormattedString;
+
/// A label widget which displays a row count and a "projection" count, the
/// number of rows in the `View` which includes aggregate rows.
pub struct StatusBarRowsCounter {}
@@ -66,10 +67,10 @@ impl Component for StatusBarRowsCounter {
..
},
) if vc != tc => {
- let vrows = vr.to_formatted_string(&Locale::en);
- let nrows = tr.to_formatted_string(&Locale::en);
- let vcols = vc.to_formatted_string(&Locale::en);
- let ncols = tc.to_formatted_string(&Locale::en);
+ let vrows = vr.to_formatted_string();
+ let nrows = tr.to_formatted_string();
+ let vcols = vc.to_formatted_string();
+ let ncols = tc.to_formatted_string();
html! {
{ format!("{} ({}) x {} ({})", vrows, nrows, vcols, ncols) } }
},
@@ -87,9 +88,9 @@ impl Component for StatusBarRowsCounter {
..
},
) => {
- let vrows = vr.to_formatted_string(&Locale::en);
- let nrows = tr.to_formatted_string(&Locale::en);
- let vcols = vc.to_formatted_string(&Locale::en);
+ let vrows = vr.to_formatted_string();
+ let nrows = tr.to_formatted_string();
+ let vcols = vc.to_formatted_string();
html! {
{ format!("{} ({}) x {}", vrows, nrows, vcols) } }
},
@@ -98,9 +99,9 @@ impl Component for StatusBarRowsCounter {
num_view_cells: Some((vr, vc)),
..
}) if vc != tc => {
- let vrows = vr.to_formatted_string(&Locale::en);
- let vcols = vc.to_formatted_string(&Locale::en);
- let ncols = tc.to_formatted_string(&Locale::en);
+ let vrows = vr.to_formatted_string();
+ let vcols = vc.to_formatted_string();
+ let ncols = tc.to_formatted_string();
html! {
{ format!("{} x {} ({})", vrows, vcols, ncols) } }
},
@@ -108,8 +109,8 @@ impl Component for StatusBarRowsCounter {
num_table_cells: Some((tr, tc)),
..
}) => {
- let nrows = tr.to_formatted_string(&Locale::en);
- let ncols = tc.to_formatted_string(&Locale::en);
+ let nrows = tr.to_formatted_string();
+ let ncols = tc.to_formatted_string();
html! {
{ format!("{} x {}", nrows, ncols) } }
},
Some(ViewStats {
diff --git a/rust/perspective-viewer/src/rust/components/string_column_style.rs b/rust/perspective-viewer/src/rust/components/string_column_style.rs
index 5ae96de51d..ee17001760 100644
--- a/rust/perspective-viewer/src/rust/components/string_column_style.rs
+++ b/rust/perspective-viewer/src/rust/components/string_column_style.rs
@@ -147,13 +147,13 @@ impl Component for StringColumnStyle {
let color_mode_changed = ctx.link().callback(StringColumnStyleMsg::ColorModeChanged);
let color_controls = match selected_color_mode {
StringColorMode::Foreground => {
- self.color_select_row(ctx, &StringColorMode::Foreground, "Foreground")
+ self.color_select_row(ctx, &StringColorMode::Foreground, "foreground-label")
},
StringColorMode::Background => {
- self.color_select_row(ctx, &StringColorMode::Background, "Background")
+ self.color_select_row(ctx, &StringColorMode::Background, "background-label")
},
StringColorMode::Series => {
- self.color_select_row(ctx, &StringColorMode::Series, "Series")
+ self.color_select_row(ctx, &StringColorMode::Series, "series-label")
},
StringColorMode::None => html! {},
};
@@ -163,12 +163,12 @@ impl Component for StringColumnStyle {
- label="Format"
+ label="format"
on_change={format_mode_changed}
current_value={format_mode_selected}
/>
- label="Color"
+ label="color"
on_change={color_mode_changed}
current_value={selected_color_mode}
/>
diff --git a/rust/perspective-viewer/src/rust/components/style_controls/number_string_format/digits_section.rs b/rust/perspective-viewer/src/rust/components/style_controls/number_string_format/digits_section.rs
index 4d8cadc61d..e3d4e76d05 100644
--- a/rust/perspective-viewer/src/rust/components/style_controls/number_string_format/digits_section.rs
+++ b/rust/perspective-viewer/src/rust/components/style_controls/number_string_format/digits_section.rs
@@ -31,7 +31,7 @@ impl CustomNumberFormat {
html! {
<>
{ self.rounding_increment(ctx) }
- // if true {
- label="Rounding Priority"
+ label="rounding-priority"
current_value={self.config.rounding_priority}
on_change={ctx.link().callback(CustomNumberFormatMsg::RoundingPriority)}
/>
- // }
- label="Rounding Mode"
+ label="rounding-mode"
current_value={self.config.rounding_mode}
on_change={ctx.link().callback(CustomNumberFormatMsg::RoundingMode)}
/>
- label="Trailing Zero Display"
+ label="trailing-zero-display"
current_value={self.config.trailing_zero_display}
on_change={ctx.link().callback(CustomNumberFormatMsg::TrailingZero)}
/>
diff --git a/rust/perspective-viewer/src/rust/components/style_controls/number_string_format/misc_section.rs b/rust/perspective-viewer/src/rust/components/style_controls/number_string_format/misc_section.rs
index bb943fd93b..8839f9d9db 100644
--- a/rust/perspective-viewer/src/rust/components/style_controls/number_string_format/misc_section.rs
+++ b/rust/perspective-viewer/src/rust/components/style_controls/number_string_format/misc_section.rs
@@ -23,7 +23,7 @@ impl CustomNumberFormat {
let cb = ctx.link().callback(CustomNumberFormatMsg::CompactDisplay);
Some(html! {
- label="Compact Display"
+ label="compact-display"
on_change={cb}
current_value={val}
/>
@@ -35,18 +35,18 @@ impl CustomNumberFormat {
html! {
<>
- label="Notation"
+ label="notation"
on_change={ctx.link().callback(CustomNumberFormatMsg::NotationChanged)}
current_value={self.notation.unwrap_or_default()}
/>
{ compact_display_checkbox }
- label="Use Grouping"
+ label="use-grouping"
on_change={ctx.link().callback(CustomNumberFormatMsg::UseGrouping)}
current_value={self.config.use_grouping.unwrap_or_default()}
/>
- label="Sign Display"
+ label="sign-display"
on_change={ctx.link().callback(CustomNumberFormatMsg::SignDisplay)}
current_value={self.config.sign_display.unwrap_or_default()}
/>
diff --git a/rust/perspective-viewer/src/rust/components/style_controls/number_string_format/style_section.rs b/rust/perspective-viewer/src/rust/components/style_controls/number_string_format/style_section.rs
index b1d48b538f..34cd9f8b74 100644
--- a/rust/perspective-viewer/src/rust/components/style_controls/number_string_format/style_section.rs
+++ b/rust/perspective-viewer/src/rust/components/style_controls/number_string_format/style_section.rs
@@ -23,17 +23,17 @@ impl CustomNumberFormat {
Some(NumberFormatStyle::Currency(style)) => Some(html! {
<>
- label="Currency"
+ label="currency"
on_change={ctx.link().callback(CustomNumberFormatMsg::CurrencyCode)}
current_value={style.currency}
/>
- label="Currency Display"
+ label="currency-display"
on_change={ctx.link().callback(CustomNumberFormatMsg::CurrencyDisplay)}
current_value={style.currency_display.unwrap_or_default()}
/>
- label="Currency Sign"
+ label="currency-sign"
on_change={ctx.link().callback(CustomNumberFormatMsg::CurrencySign)}
current_value={style.currency_sign.unwrap_or_default()}
/>
@@ -42,12 +42,12 @@ impl CustomNumberFormat {
Some(NumberFormatStyle::Unit(style)) => Some(html!(
<>
- label="Unit"
+ label="unit"
on_change={ctx.link().callback(CustomNumberFormatMsg::Unit)}
current_value={style.unit}
/>
- label="Unit Display"
+ label="unit-display"
on_change={ctx.link().callback(CustomNumberFormatMsg::UnitDisplay)}
current_value={style.unit_display.unwrap_or_default()}
/>
@@ -58,7 +58,7 @@ impl CustomNumberFormat {
html! {
<>
- label="Style"
+ label="style"
current_value={self.style}
on_change={ctx.link().callback(CustomNumberFormatMsg::StyleChanged)}
/>
diff --git a/rust/perspective-viewer/src/rust/config/columns_config.rs b/rust/perspective-viewer/src/rust/config/columns_config.rs
index a0cd80f0ca..05ebe028f5 100644
--- a/rust/perspective-viewer/src/rust/config/columns_config.rs
+++ b/rust/perspective-viewer/src/rust/config/columns_config.rs
@@ -16,9 +16,9 @@ use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use super::{
- CustomDatetimeFormat, CustomNumberFormatConfig, DatetimeColumnStyleConfig,
- DatetimeColumnStyleDefaultConfig, NumberColumnStyleConfig, NumberColumnStyleDefaultConfig,
- StringColumnStyleConfig, StringColumnStyleDefaultConfig,
+ CustomNumberFormatConfig, DatetimeColumnStyleConfig, DatetimeColumnStyleDefaultConfig,
+ NumberColumnStyleConfig, NumberColumnStyleDefaultConfig, StringColumnStyleConfig,
+ StringColumnStyleDefaultConfig,
};
/// The value de/serialized and stored in the viewer config.
diff --git a/rust/perspective-viewer/src/rust/config/number_string_format.rs b/rust/perspective-viewer/src/rust/config/number_string_format.rs
index 30e472ae39..02c3127d4f 100644
--- a/rust/perspective-viewer/src/rust/config/number_string_format.rs
+++ b/rust/perspective-viewer/src/rust/config/number_string_format.rs
@@ -16,8 +16,6 @@ use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use strum::{Display, EnumIter};
-use crate::max;
-
#[derive(Serialize, Deserialize, Default, Debug, PartialEq, Clone)]
#[serde(rename_all = "camelCase", tag = "style")]
pub enum NumberFormatStyle {
diff --git a/rust/perspective-viewer/src/rust/utils/mod.rs b/rust/perspective-viewer/src/rust/utils/mod.rs
index 283c789ec5..f22d2b7f34 100644
--- a/rust/perspective-viewer/src/rust/utils/mod.rs
+++ b/rust/perspective-viewer/src/rust/utils/mod.rs
@@ -25,6 +25,7 @@ mod debounce;
mod errors;
mod futures;
mod json;
+mod number_format;
mod pubsub;
mod scope;
mod serde;
@@ -42,6 +43,7 @@ pub use custom_element::*;
pub use datetime::*;
pub use debounce::*;
pub use errors::*;
+pub use number_format::*;
pub use pubsub::*;
pub use scope::*;
pub use tee::*;
diff --git a/rust/perspective-viewer/src/rust/utils/number_format.rs b/rust/perspective-viewer/src/rust/utils/number_format.rs
new file mode 100644
index 0000000000..5616d4961c
--- /dev/null
+++ b/rust/perspective-viewer/src/rust/utils/number_format.rs
@@ -0,0 +1,49 @@
+// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
+// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
+// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
+// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
+// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
+// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
+// ┃ Copyright (c) 2017, the Perspective Authors. ┃
+// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
+// ┃ This file is part of the Perspective library, distributed under the terms ┃
+// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
+// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
+
+use std::sync::LazyLock;
+
+use js_sys::Intl;
+use wasm_bindgen::JsValue;
+
+use super::global::navigator;
+use crate::json;
+
+pub trait ToFormattedString {
+ fn to_formatted_string(&self) -> String;
+}
+
+struct UnsafeNumberFormat(Intl::NumberFormat);
+
+unsafe impl Send for UnsafeNumberFormat {}
+unsafe impl Sync for UnsafeNumberFormat {}
+
+static NUMBER_FORMAT: LazyLock = LazyLock::new(|| {
+ let locale = navigator().languages();
+ let opts = json!({});
+ let number_format = Intl::NumberFormat::new(&locale, &opts);
+ UnsafeNumberFormat(number_format)
+});
+
+impl UnsafeNumberFormat {}
+
+impl ToFormattedString for u32 {
+ fn to_formatted_string(&self) -> String {
+ NUMBER_FORMAT
+ .0
+ .format()
+ .call1(&NUMBER_FORMAT.0, &JsValue::from_f64(*self as f64))
+ .unwrap()
+ .as_string()
+ .unwrap()
+ }
+}
diff --git a/rust/perspective-viewer/src/themes/icons.less b/rust/perspective-viewer/src/themes/icons.less
index bccb4253ad..08fc6ba2cc 100644
--- a/rust/perspective-viewer/src/themes/icons.less
+++ b/rust/perspective-viewer/src/themes/icons.less
@@ -20,7 +20,6 @@ perspective-number-column-style,
perspective-string-column-style {
@include perspective-viewer-base--icons;
@include perspective-viewer-base--colors;
- @include perspective-viewer-base--intl;
@include perspective-viewer-base--datagrid;
}
@@ -71,21 +70,11 @@ perspective-string-column-style {
--sort-none-icon--mask-image: url("../svg/sort-none-icon.svg");
--add-expression-icon--mask-image: url("../svg/expression.svg");
--close-icon--mask-image: url("../svg/close-icon.svg");
-}
-
-@mixin perspective-viewer-base--intl {
- // Query overlay labels
- --group_by--content: "Group By";
- --split_by--content: "Split By";
-
- // Icons
--inactive-column-selector--content: url("../svg/checkbox-unchecked-icon.svg");
--active-column-selector--content: url("../svg/checkbox-checked-icon.svg");
--overflow-hint-icon--content: "!";
--reset-button-icon--content: "refresh";
--save-button-icon--content: "save";
- --transpose-button--content: "Swap";
- --config-button-icon--content: "configure";
}
@mixin perspective-viewer-base--datagrid {
diff --git a/rust/perspective-viewer/src/themes/intl.less b/rust/perspective-viewer/src/themes/intl.less
new file mode 100644
index 0000000000..8a2d83c8ec
--- /dev/null
+++ b/rust/perspective-viewer/src/themes/intl.less
@@ -0,0 +1,97 @@
+// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
+// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
+// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
+// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
+// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
+// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
+// ┃ Copyright (c) 2017, the Perspective Authors. ┃
+// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
+// ┃ This file is part of the Perspective library, distributed under the terms ┃
+// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
+// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
+
+perspective-viewer,
+perspective-dropdown {
+ // Config
+ --group-by-label--content: "Group By";
+ --split-by-label--content: "Split By";
+ --sort-label--content: "Order By";
+ --filter-label--content: "Where";
+ --transpose-button--content: "Swap";
+ --config-button-icon--content: "configure";
+ --all-columns-label--content: "All Columns";
+ --untitled--content: "untitled";
+
+ // Plugin names
+ --plugin-name-datagrid--content: "Datagrid";
+ --plugin-name-treemap--content: "Treemap";
+ --plugin-name-sunburst--content: "Sunburst";
+ --plugin-name-heatmap--content: "Heatmap";
+ --plugin-name-x-bar--content: "X Bar";
+ --plugin-name-y-bar--content: "Y Bar";
+ --plugin-name-y-line--content: "Y Line";
+ --plugin-name-x-y-line--content: "X/Y Line";
+ --plugin-name-x-y-scatter--content: "X/Y Scatter";
+ --plugin-name-y-scatter--content: "Y Scatter";
+ --plugin-name-y-area--content: "Y Area";
+ --plugin-name-ohlc--content: "OHLC";
+ --plugin-name-candlestick--content: "Candlestick";
+
+ // Column Selector names
+ --column-selector-column-columns--content: "Columns";
+ --column-selector-column-x-axis--content: "X Axis";
+ --column-selector-column-y-axis--content: "Y Axis";
+ --column-selector-column-color--content: "Color";
+ --column-selector-column-size--content: "Size";
+ --column-selector-column-symbol--content: "Symbol";
+ --column-selector-column-label--content: "Label";
+ --column-selector-column-tooltip--content: "Tooltip";
+ --add-expression-button--content: "New Column";
+
+ // Toolbar
+ --no-results--content: "Invalid Column";
+ --datagrid-column-edit-button--content: "Edit";
+ --copy-button--content: "Copy";
+ --export-button--content: "Export";
+ --reset-button--content: "Reset";
+ --edit-mode-toggle--content: "Read Only";
+ --edit-mode-alt-toggle--content: "Editbale";
+ --scroll-lock-toggle--content: "Free Scroll";
+ --scroll-lock-alt-toggle--content: "Align Scroll";
+
+ // Column Settings
+ --color-label--content: "Color";
+ --format-label--content: "Format";
+ --timezone-label--content: "Timezone";
+ --date-style-label--content: "Date Style";
+ --time-style-label--content: "Time Style";
+ --foreground-label--content: "Foreground";
+ --background-label--content: "Background";
+ --series-label--content: "Series";
+ --color-range-label--content: "Color Range";
+ --style-label--content: "Style";
+ --minimum-integer-digits-label--content: "Minimum Integer Digits";
+ --rounding-increment-label--content: "Rounding Increment";
+ --notation-label--content: "Notation";
+ --use-grouping-label--content: "Use Grouping";
+ --sign-display-label--content: "Sign Display";
+ --max-value-label--content: "Max Value";
+ --rounding-priority-label--content: "Rounding Priority";
+ --rounding-mode-label--content: "Rounding Mode";
+ --trailing-zero-display-label--content: "Trailing Zero Display";
+ --fractional-digits-label--content: "Fractional Digits";
+ --significant-digits-label--content: "Significant Digits";
+ --year-label--content: "Year";
+ --month-label--content: "Month";
+ --day-label--content: "Day";
+ --weekday-label--content: "Weekday";
+ --hour-label--content: "Hour";
+ --minute-label--content: "Minute";
+ --second-label--content: "Second";
+ --fractional-seconds-label--content: "Fractional Seconds";
+ --hours-label--content: "12/24 Hours";
+
+ // Tabs
+ --style-tab-label--content: "Style";
+ --attributes-tab-label--content: "Attributes";
+}
diff --git a/rust/perspective-viewer/src/themes/intl/de.less b/rust/perspective-viewer/src/themes/intl/de.less
new file mode 100644
index 0000000000..dc55fe0687
--- /dev/null
+++ b/rust/perspective-viewer/src/themes/intl/de.less
@@ -0,0 +1,97 @@
+// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
+// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
+// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
+// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
+// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
+// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
+// ┃ Copyright (c) 2017, the Perspective Authors. ┃
+// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
+// ┃ This file is part of the Perspective library, distributed under the terms ┃
+// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
+// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
+
+perspective-viewer,
+perspective-dropdown {
+ // Config
+ --group-by-label--content: "Gruppiere nach";
+ --split-by-label--content: "Geteilt nach";
+ --sort-label--content: "Sortieren nach";
+ --filter-label--content: "Wo";
+ --transpose-button--content: "Tauschen";
+ --config-button-icon--content: "Konfigurieren";
+ --all-columns-label--content: "Alle Spalten";
+ --untitled--content: "Ohne Titel";
+
+ // Plugin names
+ --plugin-name-datagrid--content: "Datengitter";
+ --plugin-name-treemap--content: "Baumkarte";
+ --plugin-name-sunburst--content: "Sonnendurchbruch";
+ --plugin-name-heatmap--content: "Heatmap";
+ --plugin-name-x-bar--content: "X-Bar";
+ --plugin-name-y-bar--content: "Und Bar";
+ --plugin-name-y-line--content: "und Linie";
+ --plugin-name-x-y-line--content: "X/Y-Linie";
+ --plugin-name-x-y-scatter--content: "X/Y-Streuung";
+ --plugin-name-y-scatter--content: "Y-Scatter";
+ --plugin-name-y-area--content: "und Bereich";
+ --plugin-name-ohlc--content: "Autsch";
+ --plugin-name-candlestick--content: "Leuchter";
+
+ // Column Selector names
+ --column-selector-column-columns--content: "Säulen";
+ --column-selector-column-x-axis--content: "X-Achse";
+ --column-selector-column-y-axis--content: "Y-Achse";
+ --column-selector-column-color--content: "Farbe";
+ --column-selector-column-size--content: "Größe";
+ --column-selector-column-symbol--content: "Symbol";
+ --column-selector-column-label--content: "Etikett";
+ --column-selector-column-tooltip--content: "Tooltip";
+ --add-expression-button--content: "Neue Spalte";
+
+ // Toolbar
+ --no-results--content: "Ungültige Spalte";
+ --datagrid-column-edit-button--content: "Bearbeiten";
+ --copy-button--content: "Kopieren";
+ --export-button--content: "Export";
+ --reset-button--content: "Zurücksetzen";
+ --edit-mode-toggle--content: "Schreibgeschützt";
+ --edit-mode-alt-toggle--content: "Editbale";
+ --scroll-lock-toggle--content: "Kostenlose Schriftrolle";
+ --scroll-lock-alt-toggle--content: "Bildlauf ausrichten";
+
+ // Column Settings
+ --color-label--content: "Farbe";
+ --format-label--content: "Format";
+ --timezone-label--content: "Zeitzone";
+ --date-style-label--content: "Datumsstil";
+ --time-style-label--content: "Zeitstil";
+ --foreground-label--content: "Vordergrund";
+ --background-label--content: "Hintergrund";
+ --series-label--content: "Serie";
+ --color-range-label--content: "Farbspektrum";
+ --style-label--content: "Stil";
+ --minimum-integer-digits-label--content: "Mindestanzahl ganzzahliger Ziffern";
+ --rounding-increment-label--content: "Rundungsinkrement";
+ --notation-label--content: "Notation";
+ --use-grouping-label--content: "Verwenden Sie Gruppierung";
+ --sign-display-label--content: "Schilderanzeige";
+ --max-value-label--content: "Maximaler Wert";
+ --rounding-priority-label--content: "Rundungspriorität";
+ --rounding-mode-label--content: "Rundungsmodus";
+ --trailing-zero-display-label--content: "Anzeige der nachgestellten Null";
+ --fractional-digits-label--content: "Bruchstellen";
+ --significant-digits-label--content: "Wichtige Ziffer";
+ --year-label--content: "Jahr";
+ --month-label--content: "Monat";
+ --day-label--content: "Tag";
+ --weekday-label--content: "Wochentag";
+ --hour-label--content: "Stunde";
+ --minute-label--content: "Minute";
+ --second-label--content: "Zweite";
+ --fractional-seconds-label--content: "Sekundenbruchteile";
+ --hours-label--content: "12/24 Stunden";
+
+ // Tabs
+ --style-tab-label--content: "Stil";
+ --attributes-tab-label--content: "Attribute";
+}
diff --git a/rust/perspective-viewer/src/themes/intl/es.less b/rust/perspective-viewer/src/themes/intl/es.less
new file mode 100644
index 0000000000..1c92088ce2
--- /dev/null
+++ b/rust/perspective-viewer/src/themes/intl/es.less
@@ -0,0 +1,97 @@
+// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
+// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
+// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
+// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
+// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
+// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
+// ┃ Copyright (c) 2017, the Perspective Authors. ┃
+// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
+// ┃ This file is part of the Perspective library, distributed under the terms ┃
+// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
+// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
+
+perspective-viewer,
+perspective-dropdown {
+ // Config
+ --group-by-label--content: "Agrupar por";
+ --split-by-label--content: "Dividir por";
+ --sort-label--content: "Ordenar por";
+ --filter-label--content: "Dónde";
+ --transpose-button--content: "Intercambio";
+ --config-button-icon--content: "Configurar";
+ --all-columns-label--content: "Todas las columnas";
+ --untitled--content: "Intitulado";
+
+ // Plugin names
+ --plugin-name-datagrid--content: "Cuadrícula de datos";
+ --plugin-name-treemap--content: "Mapa de árbol";
+ --plugin-name-sunburst--content: "resplandor solar";
+ --plugin-name-heatmap--content: "Mapa de calor";
+ --plugin-name-x-bar--content: "Barra X";
+ --plugin-name-y-bar--content: "Y Bar";
+ --plugin-name-y-line--content: "Y Line";
+ --plugin-name-x-y-line--content: "Línea X/Y";
+ --plugin-name-x-y-scatter--content: "Dispersión X/Y";
+ --plugin-name-y-scatter--content: "Dispersión Y";
+ --plugin-name-y-area--content: "Y Area";
+ --plugin-name-ohlc--content: "Ay";
+ --plugin-name-candlestick--content: "Candelero";
+
+ // Column Selector names
+ --column-selector-column-columns--content: "columnas";
+ --column-selector-column-x-axis--content: "Eje X";
+ --column-selector-column-y-axis--content: "Y Axis";
+ --column-selector-column-color--content: "Color";
+ --column-selector-column-size--content: "Tamaño";
+ --column-selector-column-symbol--content: "Símbolo";
+ --column-selector-column-label--content: "Etiqueta";
+ --column-selector-column-tooltip--content: "Información sobre herramientas";
+ --add-expression-button--content: "Nueva columna";
+
+ // Toolbar
+ --no-results--content: "Columna no válida";
+ --datagrid-column-edit-button--content: "Editar";
+ --copy-button--content: "Copiar";
+ --export-button--content: "Exportar";
+ --reset-button--content: "Reiniciar";
+ --edit-mode-toggle--content: "Solo lectura";
+ --edit-mode-alt-toggle--content: "Editable";
+ --scroll-lock-toggle--content: "Desplazamiento libre";
+ --scroll-lock-alt-toggle--content: "Alinear desplazamiento";
+
+ // Column Settings
+ --color-label--content: "Color";
+ --format-label--content: "Formato";
+ --timezone-label--content: "Zona horaria";
+ --date-style-label--content: "Estilo de fecha";
+ --time-style-label--content: "Estilo de hora";
+ --foreground-label--content: "Primer plano";
+ --background-label--content: "Fondo";
+ --series-label--content: "Serie";
+ --color-range-label--content: "Gama de colores";
+ --style-label--content: "Estilo";
+ --minimum-integer-digits-label--content: "Dígitos enteros mínimos";
+ --rounding-increment-label--content: "Incremento de redondeo";
+ --notation-label--content: "Notación";
+ --use-grouping-label--content: "Usar agrupación";
+ --sign-display-label--content: "Visualización de letreros";
+ --max-value-label--content: "Valor máximo";
+ --rounding-priority-label--content: "Prioridad de redondeo";
+ --rounding-mode-label--content: "Modo de redondeo";
+ --trailing-zero-display-label--content: "Visualización del cero final";
+ --fractional-digits-label--content: "Dígitos fraccionarios";
+ --significant-digits-label--content: "Dígitos significantes";
+ --year-label--content: "Año";
+ --month-label--content: "Mes";
+ --day-label--content: "Día";
+ --weekday-label--content: "Día laborable";
+ --hour-label--content: "Hora";
+ --minute-label--content: "Minuto";
+ --second-label--content: "Segundo";
+ --fractional-seconds-label--content: "Segundos fraccionarios";
+ --hours-label--content: "12/24 Horas";
+
+ // Tabs
+ --style-tab-label--content: "Estilo";
+ --attributes-tab-label--content: "Atributos";
+}
diff --git a/rust/perspective-viewer/src/themes/intl/fr.less b/rust/perspective-viewer/src/themes/intl/fr.less
new file mode 100644
index 0000000000..36f5472716
--- /dev/null
+++ b/rust/perspective-viewer/src/themes/intl/fr.less
@@ -0,0 +1,97 @@
+// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
+// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
+// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
+// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
+// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
+// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
+// ┃ Copyright (c) 2017, the Perspective Authors. ┃
+// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
+// ┃ This file is part of the Perspective library, distributed under the terms ┃
+// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
+// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
+
+perspective-viewer,
+perspective-dropdown {
+ // Config
+ --group-by-label--content: "Par groupe";
+ --split-by-label--content: "Divisé par";
+ --sort-label--content: "Commandé par";
+ --filter-label--content: "Où";
+ --transpose-button--content: "Échanger";
+ --config-button-icon--content: "Configurer";
+ --all-columns-label--content: "Toutes les colonnes";
+ --untitled--content: "Sans titre";
+
+ // Plugin names
+ --plugin-name-datagrid--content: "Grille de données";
+ --plugin-name-treemap--content: "Treemap";
+ --plugin-name-sunburst--content: "Coup de soleil";
+ --plugin-name-heatmap--content: "Carte de chaleur";
+ --plugin-name-x-bar--content: "Barre X";
+ --plugin-name-y-bar--content: "Et le bar";
+ --plugin-name-y-line--content: "et ligne";
+ --plugin-name-x-y-line--content: "Ligne X/Y";
+ --plugin-name-x-y-scatter--content: "Dispersion X/Y";
+ --plugin-name-y-scatter--content: "Dispersion Y";
+ --plugin-name-y-area--content: "et la superficie";
+ --plugin-name-ohlc--content: "Aie";
+ --plugin-name-candlestick--content: "Chandelier";
+
+ // Column Selector names
+ --column-selector-column-columns--content: "Colonnes";
+ --column-selector-column-x-axis--content: "Axe X";
+ --column-selector-column-y-axis--content: "Axe Y";
+ --column-selector-column-color--content: "Couleur";
+ --column-selector-column-size--content: "Taille";
+ --column-selector-column-symbol--content: "Symbole";
+ --column-selector-column-label--content: "Étiquette";
+ --column-selector-column-tooltip--content: "Info-bulle";
+ --add-expression-button--content: "Nouvelle colonne";
+
+ // Toolbar
+ --no-results--content: "Colonne invalide";
+ --datagrid-column-edit-button--content: "Modifier";
+ --copy-button--content: "Copie";
+ --export-button--content: "Exporter";
+ --reset-button--content: "Réinitialiser";
+ --edit-mode-toggle--content: "Lecture seulement";
+ --edit-mode-alt-toggle--content: "Editbale";
+ --scroll-lock-toggle--content: "Défilement gratuit";
+ --scroll-lock-alt-toggle--content: "Aligner le défilement";
+
+ // Column Settings
+ --color-label--content: "Couleur";
+ --format-label--content: "Format";
+ --timezone-label--content: "Fuseau horaire";
+ --date-style-label--content: "Style de date";
+ --time-style-label--content: "Style temporel";
+ --foreground-label--content: "Premier plan";
+ --background-label--content: "Arrière-plan";
+ --series-label--content: "Série";
+ --color-range-label--content: "Gamme de couleurs";
+ --style-label--content: "Style";
+ --minimum-integer-digits-label--content: "Chiffres entiers minimaux";
+ --rounding-increment-label--content: "Incrément d'arrondi";
+ --notation-label--content: "Notation";
+ --use-grouping-label--content: "Utiliser le regroupement";
+ --sign-display-label--content: "Affichage des panneaux";
+ --max-value-label--content: "Valeur max";
+ --rounding-priority-label--content: "Priorité d'arrondi";
+ --rounding-mode-label--content: "Mode d'arrondi";
+ --trailing-zero-display-label--content: "Affichage du zéro final";
+ --fractional-digits-label--content: "Chiffres fractionnaires";
+ --significant-digits-label--content: "Chiffres significatifs";
+ --year-label--content: "Année";
+ --month-label--content: "Mois";
+ --day-label--content: "Jour";
+ --weekday-label--content: "Jour de la semaine";
+ --hour-label--content: "Heure";
+ --minute-label--content: "Minute";
+ --second-label--content: "Deuxième";
+ --fractional-seconds-label--content: "Fractions de secondes";
+ --hours-label--content: "12/24 heures";
+
+ // Tabs
+ --style-tab-label--content: "Style";
+ --attributes-tab-label--content: "Les attributs";
+}
diff --git a/rust/perspective-viewer/src/themes/intl/ja.less b/rust/perspective-viewer/src/themes/intl/ja.less
new file mode 100644
index 0000000000..51024d8310
--- /dev/null
+++ b/rust/perspective-viewer/src/themes/intl/ja.less
@@ -0,0 +1,97 @@
+// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
+// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
+// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
+// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
+// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
+// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
+// ┃ Copyright (c) 2017, the Perspective Authors. ┃
+// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
+// ┃ This file is part of the Perspective library, distributed under the terms ┃
+// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
+// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
+
+perspective-viewer,
+perspective-dropdown {
+ // Config
+ --group-by-label--content: "グループ化";
+ --split-by-label--content: "分割";
+ --sort-label--content: "注文方法";
+ --filter-label--content: "どこ";
+ --transpose-button--content: "スワップ";
+ --config-button-icon--content: "構成、設定";
+ --all-columns-label--content: "すべての列";
+ --untitled--content: "無題";
+
+ // Plugin names
+ --plugin-name-datagrid--content: "データグリッド";
+ --plugin-name-treemap--content: "ツリーマップ";
+ --plugin-name-sunburst--content: "サンバースト";
+ --plugin-name-heatmap--content: "ヒートマップ";
+ --plugin-name-x-bar--content: "Xバー";
+ --plugin-name-y-bar--content: "アンドバー";
+ --plugin-name-y-line--content: "そしてライン";
+ --plugin-name-x-y-line--content: "X/Y ライン";
+ --plugin-name-x-y-scatter--content: "X/Y 散布図";
+ --plugin-name-y-scatter--content: "Y散布図";
+ --plugin-name-y-area--content: "とエリア";
+ --plugin-name-ohlc--content: "痛い";
+ --plugin-name-candlestick--content: "ローソク足";
+
+ // Column Selector names
+ --column-selector-column-columns--content: "コラム";
+ --column-selector-column-x-axis--content: "X軸";
+ --column-selector-column-y-axis--content: "Y軸";
+ --column-selector-column-color--content: "色";
+ --column-selector-column-size--content: "サイズ";
+ --column-selector-column-symbol--content: "シンボル";
+ --column-selector-column-label--content: "ラベル";
+ --column-selector-column-tooltip--content: "ツールチップ";
+ --add-expression-button--content: "新しい列";
+
+ // Toolbar
+ --no-results--content: "無効な列";
+ --datagrid-column-edit-button--content: "編集";
+ --copy-button--content: "コピー";
+ --export-button--content: "輸出";
+ --reset-button--content: "リセット";
+ --edit-mode-toggle--content: "読み取り専用";
+ --edit-mode-alt-toggle--content: "エディベール";
+ --scroll-lock-toggle--content: "フリースクロール";
+ --scroll-lock-alt-toggle--content: "スクロールを揃える";
+
+ // Column Settings
+ --color-label--content: "色";
+ --format-label--content: "フォーマット";
+ --timezone-label--content: "タイムゾーン";
+ --date-style-label--content: "日付スタイル";
+ --time-style-label--content: "時間スタイル";
+ --foreground-label--content: "前景";
+ --background-label--content: "背景";
+ --series-label--content: "シリーズ";
+ --color-range-label--content: "色の範囲";
+ --style-label--content: "スタイル";
+ --minimum-integer-digits-label--content: "整数の最小桁数";
+ --rounding-increment-label--content: "丸め増分";
+ --notation-label--content: "表記";
+ --use-grouping-label--content: "グループ化を使用する";
+ --sign-display-label--content: "サインディスプレイ";
+ --max-value-label--content: "最大値";
+ --rounding-priority-label--content: "丸めの優先順位";
+ --rounding-mode-label--content: "丸めモード";
+ --trailing-zero-display-label--content: "末尾ゼロの表示";
+ --fractional-digits-label--content: "小数桁";
+ --significant-digits-label--content: "有効数字";
+ --year-label--content: "年";
+ --month-label--content: "月";
+ --day-label--content: "日";
+ --weekday-label--content: "平日";
+ --hour-label--content: "時間";
+ --minute-label--content: "分";
+ --second-label--content: "2番";
+ --fractional-seconds-label--content: "小数秒";
+ --hours-label--content: "12/24時間";
+
+ // Tabs
+ --style-tab-label--content: "スタイル";
+ --attributes-tab-label--content: "属性";
+}
diff --git a/rust/perspective-viewer/src/themes/intl/pt.less b/rust/perspective-viewer/src/themes/intl/pt.less
new file mode 100644
index 0000000000..3f1ee25210
--- /dev/null
+++ b/rust/perspective-viewer/src/themes/intl/pt.less
@@ -0,0 +1,97 @@
+// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
+// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
+// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
+// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
+// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
+// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
+// ┃ Copyright (c) 2017, the Perspective Authors. ┃
+// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
+// ┃ This file is part of the Perspective library, distributed under the terms ┃
+// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
+// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
+
+perspective-viewer,
+perspective-dropdown {
+ // Config
+ --group-by-label--content: "Agrupar por";
+ --split-by-label--content: "Dividir por";
+ --sort-label--content: "Ordenar por";
+ --filter-label--content: "Onde";
+ --transpose-button--content: "Trocar";
+ --config-button-icon--content: "Configurar";
+ --all-columns-label--content: "Todas as colunas";
+ --untitled--content: "Sem título";
+
+ // Plugin names
+ --plugin-name-datagrid--content: "Grade de dados";
+ --plugin-name-treemap--content: "Mapa de árvore";
+ --plugin-name-sunburst--content: "reluzente";
+ --plugin-name-heatmap--content: "Mapa de calor";
+ --plugin-name-x-bar--content: "Barra X";
+ --plugin-name-y-bar--content: "E Barra";
+ --plugin-name-y-line--content: "e linha";
+ --plugin-name-x-y-line--content: "Linha X/Y";
+ --plugin-name-x-y-scatter--content: "Dispersão X/Y";
+ --plugin-name-y-scatter--content: "Dispersão Y";
+ --plugin-name-y-area--content: "e área";
+ --plugin-name-ohlc--content: "Ai";
+ --plugin-name-candlestick--content: "Castiçal";
+
+ // Column Selector names
+ --column-selector-column-columns--content: "Colunas";
+ --column-selector-column-x-axis--content: "Eixo X";
+ --column-selector-column-y-axis--content: "Eixo Y";
+ --column-selector-column-color--content: "Cor";
+ --column-selector-column-size--content: "Tamanho";
+ --column-selector-column-symbol--content: "Símbolo";
+ --column-selector-column-label--content: "Rótulo";
+ --column-selector-column-tooltip--content: "Dica";
+ --add-expression-button--content: "Nova Coluna";
+
+ // Toolbar
+ --no-results--content: "Coluna inválida";
+ --datagrid-column-edit-button--content: "Editar";
+ --copy-button--content: "cópia de";
+ --export-button--content: "Exportar";
+ --reset-button--content: "Reiniciar";
+ --edit-mode-toggle--content: "Somente leitura";
+ --edit-mode-alt-toggle--content: "Editar Bale";
+ --scroll-lock-toggle--content: "Rolagem Grátis";
+ --scroll-lock-alt-toggle--content: "Alinhar rolagem";
+
+ // Column Settings
+ --color-label--content: "Cor";
+ --format-label--content: "Formatar";
+ --timezone-label--content: "Fuso horário";
+ --date-style-label--content: "Estilo de data";
+ --time-style-label--content: "Estilo de tempo";
+ --foreground-label--content: "Primeiro plano";
+ --background-label--content: "Fundo";
+ --series-label--content: "Series";
+ --color-range-label--content: "Gama de cores";
+ --style-label--content: "Estilo";
+ --minimum-integer-digits-label--content: "Dígitos inteiros mínimos";
+ --rounding-increment-label--content: "Incremento de arredondamento";
+ --notation-label--content: "Notação";
+ --use-grouping-label--content: "Usar agrupamento";
+ --sign-display-label--content: "Exibição de sinalização";
+ --max-value-label--content: "Valor máximo";
+ --rounding-priority-label--content: "Prioridade de arredondamento";
+ --rounding-mode-label--content: "Modo de arredondamento";
+ --trailing-zero-display-label--content: "Exibição de zero à direita";
+ --fractional-digits-label--content: "Dígitos Fracionários";
+ --significant-digits-label--content: "Dígitos significantes";
+ --year-label--content: "Ano";
+ --month-label--content: "Mês";
+ --day-label--content: "Dia";
+ --weekday-label--content: "Dia da semana";
+ --hour-label--content: "Hora";
+ --minute-label--content: "Minuto";
+ --second-label--content: "Segundo";
+ --fractional-seconds-label--content: "Segundos fracionários";
+ --hours-label--content: "12/24 horas";
+
+ // Tabs
+ --style-tab-label--content: "Estilo";
+ --attributes-tab-label--content: "Atributos";
+}
diff --git a/rust/perspective-viewer/src/themes/intl/zh.less b/rust/perspective-viewer/src/themes/intl/zh.less
new file mode 100644
index 0000000000..2030f17bed
--- /dev/null
+++ b/rust/perspective-viewer/src/themes/intl/zh.less
@@ -0,0 +1,97 @@
+// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
+// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
+// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
+// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
+// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
+// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
+// ┃ Copyright (c) 2017, the Perspective Authors. ┃
+// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
+// ┃ This file is part of the Perspective library, distributed under the terms ┃
+// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
+// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
+
+perspective-viewer,
+perspective-dropdown {
+ // Config
+ --group-by-label--content: "通过...分组";
+ --split-by-label--content: "分割依据";
+ --sort-label--content: "订购依据";
+ --filter-label--content: "在哪里";
+ --transpose-button--content: "交换";
+ --config-button-icon--content: "配置";
+ --all-columns-label--content: "所有栏目";
+ --untitled--content: "无标题";
+
+ // Plugin names
+ --plugin-name-datagrid--content: "数据网格";
+ --plugin-name-treemap--content: "树形图";
+ --plugin-name-sunburst--content: "旭日";
+ --plugin-name-heatmap--content: "热图";
+ --plugin-name-x-bar--content: "X吧";
+ --plugin-name-y-bar--content: "和酒吧";
+ --plugin-name-y-line--content: "和线";
+ --plugin-name-x-y-line--content: "X/Y线";
+ --plugin-name-x-y-scatter--content: "X/Y 散点图";
+ --plugin-name-y-scatter--content: "Y 散点图";
+ --plugin-name-y-area--content: "和面积";
+ --plugin-name-ohlc--content: "哎哟";
+ --plugin-name-candlestick--content: "烛台";
+
+ // Column Selector names
+ --column-selector-column-columns--content: "列";
+ --column-selector-column-x-axis--content: "X轴";
+ --column-selector-column-y-axis--content: "Y轴";
+ --column-selector-column-color--content: "颜色";
+ --column-selector-column-size--content: "尺寸";
+ --column-selector-column-symbol--content: "象征";
+ --column-selector-column-label--content: "标签";
+ --column-selector-column-tooltip--content: "工具提示";
+ --add-expression-button--content: "新专栏";
+
+ // Toolbar
+ --no-results--content: "无效列";
+ --datagrid-column-edit-button--content: "编辑";
+ --copy-button--content: "复制";
+ --export-button--content: "出口";
+ --reset-button--content: "重置";
+ --edit-mode-toggle--content: "只读";
+ --edit-mode-alt-toggle--content: "伊迪特巴莱";
+ --scroll-lock-toggle--content: "自由滚动";
+ --scroll-lock-alt-toggle--content: "对齐滚动";
+
+ // Column Settings
+ --color-label--content: "颜色";
+ --format-label--content: "格式";
+ --timezone-label--content: "时区";
+ --date-style-label--content: "日期样式";
+ --time-style-label--content: "时间风格";
+ --foreground-label--content: "前景";
+ --background-label--content: "背景";
+ --series-label--content: "系列";
+ --color-range-label--content: "颜色范围";
+ --style-label--content: "风格";
+ --minimum-integer-digits-label--content: "最小整数位数";
+ --rounding-increment-label--content: "舍入增量";
+ --notation-label--content: "符号";
+ --use-grouping-label--content: "使用分组";
+ --sign-display-label--content: "标志展示";
+ --max-value-label--content: "最大值";
+ --rounding-priority-label--content: "舍入优先级";
+ --rounding-mode-label--content: "舍入模式";
+ --trailing-zero-display-label--content: "尾随零显示";
+ --fractional-digits-label--content: "小数位";
+ --significant-digits-label--content: "有效数字";
+ --year-label--content: "年";
+ --month-label--content: "月";
+ --day-label--content: "天";
+ --weekday-label--content: "工作日";
+ --hour-label--content: "小时";
+ --minute-label--content: "分钟";
+ --second-label--content: "第二";
+ --fractional-seconds-label--content: "小数秒";
+ --hours-label--content: "12/24 小时";
+
+ // Tabs
+ --style-tab-label--content: "风格";
+ --attributes-tab-label--content: "属性";
+}
diff --git a/rust/perspective-viewer/tasks/lint/main.rs b/rust/perspective-viewer/tasks/lint/main.rs
index 429c45a3b7..49569aeb86 100644
--- a/rust/perspective-viewer/tasks/lint/main.rs
+++ b/rust/perspective-viewer/tasks/lint/main.rs
@@ -34,7 +34,7 @@ pub fn main() {
let yewfmt_args = edition_args
.into_iter()
.map(|x| x.into())
- .chain(args.into_iter())
+ .chain(args)
.collect::>();
let exit_code = std::process::Command::new(env!("CARGO_BIN_FILE_YEW_FMT"))
diff --git a/rust/perspective-viewer/test/js/column_settings.spec.ts b/rust/perspective-viewer/test/js/column_settings.spec.ts
index b09f84251d..661394acdf 100644
--- a/rust/perspective-viewer/test/js/column_settings.spec.ts
+++ b/rust/perspective-viewer/test/js/column_settings.spec.ts
@@ -35,18 +35,18 @@ export async function checkTab(
if (active) {
if (expression) {
if (hasStyles) {
- expect(await titles[0].innerText()).toBe("Style");
- expect(await titles[1].innerText()).toBe("Attributes");
+ expect(await titles[0].getAttribute("id")).toBe("Style");
+ expect(await titles[1].getAttribute("id")).toBe("Attributes");
} else {
- expect(await titles[0].innerText()).toBe("Attributes");
+ expect(await titles[0].getAttribute("id")).toBe("Attributes");
}
} else {
- expect(await titles[0].innerText()).toBe("Style");
+ expect(await titles[0].getAttribute("id")).toBe("Style");
}
} else {
if (expression) {
expect(titles.length).toBe(1);
- expect(await titles[0].innerText()).toBe("Attributes");
+ expect(await titles[0].getAttribute("id")).toBe("Attributes");
} else {
test.fail(
true,
@@ -184,7 +184,9 @@ test.describe("Plugin Styles", () => {
await view.columnSettingsSidebar.openTab("Attributes");
await checkTab(view.columnSettingsSidebar, false, true);
const selectedTab = async () => {
- return await view.columnSettingsSidebar.selectedTab.innerText();
+ return await view.columnSettingsSidebar.selectedTab
+ .locator(".tab-title")
+ .getAttribute("id");
};
expect(await selectedTab()).toBe("Attributes");
await col.activeBtn.click();
diff --git a/rust/perspective-viewer/test/js/column_settings/datagrid.spec.ts b/rust/perspective-viewer/test/js/column_settings/datagrid.spec.ts
index 73a8f77447..a787f9081f 100644
--- a/rust/perspective-viewer/test/js/column_settings/datagrid.spec.ts
+++ b/rust/perspective-viewer/test/js/column_settings/datagrid.spec.ts
@@ -178,7 +178,7 @@ runTests("Datagrid Column Styles", () => {
await td.waitFor();
// bg style
- await view.columnSettingsSidebar.openTab("style");
+ await view.columnSettingsSidebar.openTab("Style");
let oldContents = await td.evaluate((node) => node.innerHTML);
let listener = await view.getEventListener(
@@ -203,7 +203,7 @@ runTests("Datagrid Column Styles", () => {
// text style
view.assureColumnSettingsOpen(col);
- await view.columnSettingsSidebar.openTab("style");
+ await view.columnSettingsSidebar.openTab("Style");
let checkbox = view.columnSettingsSidebar.container
.getByRole("checkbox", { disabled: false })
.first();
@@ -238,7 +238,7 @@ runTests("Datagrid Column Styles", () => {
// bg color
await view.assureColumnSettingsOpen(col);
- await view.columnSettingsSidebar.openTab("style");
+ await view.columnSettingsSidebar.openTab("Style");
let container = view.columnSettingsSidebar.container;
let checkbox = container.getByRole("checkbox").last();
await checkbox.waitFor();
diff --git a/rust/perspective-viewer/test/js/column_settings/interactions.spec.ts b/rust/perspective-viewer/test/js/column_settings/interactions.spec.ts
index 8f0c13ad6a..5b8af2e596 100644
--- a/rust/perspective-viewer/test/js/column_settings/interactions.spec.ts
+++ b/rust/perspective-viewer/test/js/column_settings/interactions.spec.ts
@@ -286,16 +286,32 @@ async function checkOutput(
tabs: string[],
unexpected_tabs: string[]
) => {
- await view.columnSettingsSidebar.container
- .locator(".tab.selected")
- .getByText(selectedTab)
- .waitFor();
+ if (selectedTab === "") {
+ await view.columnSettingsSidebar.container
+ .locator(".tab.selected .tab-title")
+ .first()
+ .waitFor();
+ } else {
+ await view.columnSettingsSidebar.container
+ .locator(`.tab.selected #${selectedTab}`)
+ .waitFor();
+ }
+
for (let tab of tabs) {
- await view.columnSettingsSidebar.tabTitle.getByText(tab).waitFor();
+ if (tab === "") {
+ await view.columnSettingsSidebar.container
+ .locator(`.tab-title`)
+ .first()
+ .waitFor();
+ } else {
+ await view.columnSettingsSidebar.container
+ .locator(`#${tab}`)
+ .waitFor();
+ }
}
for (let tab of unexpected_tabs) {
await view.columnSettingsSidebar.tabTitle
- .getByText(tab)
+ .locator(`#${tab}`)
.waitFor({ state: "hidden" });
}
};
@@ -622,7 +638,7 @@ test.describe("Unique Behaviors", () => {
true
);
await date.editBtn.click();
- await view.columnSettingsSidebar.openTab("style");
+ await view.columnSettingsSidebar.openTab("Style");
const dateSnapshot =
await view.columnSettingsSidebar.styleTab.container.innerHTML();
const datetime = await view.settingsPanel.activeColumns.getColumnByName(
diff --git a/rust/perspective-viewer/test/js/column_settings/number_string_format.spec.ts b/rust/perspective-viewer/test/js/column_settings/number_string_format.spec.ts
index e75ec8a4a7..48876233ae 100644
--- a/rust/perspective-viewer/test/js/column_settings/number_string_format.spec.ts
+++ b/rust/perspective-viewer/test/js/column_settings/number_string_format.spec.ts
@@ -42,7 +42,7 @@ test("Integer/float styles", async ({ page }) => {
);
await profit.editBtn.click();
const styleContainer = view.columnSettingsSidebar.styleTab.container;
- await styleContainer.getByText("Fractional Digits").waitFor();
+ await styleContainer.locator("#fractional-digits-label").waitFor();
const rowId = await view.settingsPanel.activeColumns.getColumnByName(
"Row ID"
);
@@ -114,7 +114,6 @@ test.skip("Rounding Priority doesn't send unless Fractional and Significant Digi
const select = styleContainer
.locator('div[data-value="Auto"] select')
.nth(1);
-
await select.scrollIntoViewIfNeeded();
await select.selectOption("MorePrecision");
const config = await view.save();
diff --git a/rust/perspective-viewer/test/js/intl.spec.js b/rust/perspective-viewer/test/js/intl.spec.js
new file mode 100644
index 0000000000..996e4b1579
--- /dev/null
+++ b/rust/perspective-viewer/test/js/intl.spec.js
@@ -0,0 +1,64 @@
+// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
+// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
+// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
+// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
+// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
+// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
+// ┃ Copyright (c) 2017, the Perspective Authors. ┃
+// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
+// ┃ This file is part of the Perspective library, distributed under the terms ┃
+// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
+// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
+
+import { PageView as PspViewer } from "@finos/perspective-test";
+import { expect, test } from "@finos/perspective-test";
+import fs from "node:fs";
+
+test.describe("Localization", function () {
+ test.beforeEach(async ({ page }) => {
+ await page.goto("/tools/perspective-test/src/html/basic-test.html");
+ await page.evaluate(async () => {
+ while (!window["__TEST_PERSPECTIVE_READY__"]) {
+ await new Promise((x) => setTimeout(x, 10));
+ }
+ });
+ });
+
+ test("All label tags are empty", async function ({ page }) {
+ const view = new PspViewer(page);
+ await view.openSettingsPanel();
+ const editBtn = view.dataGrid.regularTable.editBtnRow
+ .locator("th.psp-menu-enabled span")
+ .first();
+
+ await editBtn.click();
+ await view.columnSettingsSidebar.container.waitFor();
+ const contents = await page.evaluate(() => {
+ const viewer = document.querySelector("perspective-viewer");
+ return Array.from(viewer.shadowRoot.querySelectorAll("label"))
+ .map((x) => x.textContent)
+ .filter((x) => x != "");
+ });
+
+ expect(contents).toEqual(["+", "-"]);
+ });
+
+ const intl = fs
+ .readFileSync(`${__dirname}/../../src/themes/intl.less`)
+ .toString();
+
+ const keys = Array.from(intl.matchAll(/--[a-zA-Z0-9\-]+/g)).flat();
+ const langfiles = fs.readdirSync(`${__dirname}/../../src/themes/intl`);
+ for (const file of langfiles) {
+ test(`${file} has all intl keys present`, async function ({ page }) {
+ const langfile = fs
+ .readFileSync(`${__dirname}/../../src/themes/intl/${file}`)
+ .toString();
+ for (const key of keys) {
+ const re = new RegExp(key, "g");
+ const x = langfile.match(re);
+ expect(x).toEqual([key]);
+ }
+ });
+ }
+});
diff --git a/tools/perspective-scripts/lint.mjs b/tools/perspective-scripts/lint.mjs
index 8f17244c9b..9a88fd29d7 100644
--- a/tools/perspective-scripts/lint.mjs
+++ b/tools/perspective-scripts/lint.mjs
@@ -30,7 +30,7 @@ export function lint_js(is_fix = false) {
const fix = is_fix ? "--fix" : undefined;
cmd.sh`cd rust/perspective-viewer`;
cmd.sh`cargo build -p perspective-lint --release`;
- cmd.sh`cargo clippy ${fix} ${dirty} ${staged}`;
+ cmd.sh`cargo clippy ${fix} ${dirty} ${staged} -- -Dwarnings`;
cmd.sh`RUSTFMT="target/release/lint" cargo fmt ${check}`;
cmd.runSync();
}
diff --git a/tools/perspective-test/playwright.config.ts b/tools/perspective-test/playwright.config.ts
index 11e19b0915..13fa82ab12 100644
--- a/tools/perspective-test/playwright.config.ts
+++ b/tools/perspective-test/playwright.config.ts
@@ -154,7 +154,7 @@ const PROJECTS = (() => {
// See https://playwright.dev/docs/test-configuration.
export default defineConfig({
- timeout: 60_000,
+ timeout: 30_000,
expect: {
timeout: 10_000,
},
diff --git a/tools/perspective-test/results.tar.gz b/tools/perspective-test/results.tar.gz
index 8ed1af6cb7..2ca37e757f 100644
Binary files a/tools/perspective-test/results.tar.gz and b/tools/perspective-test/results.tar.gz differ
diff --git a/tools/perspective-test/src/js/models/column_settings.ts b/tools/perspective-test/src/js/models/column_settings.ts
index 538d93ada4..55a1e3f17a 100644
--- a/tools/perspective-test/src/js/models/column_settings.ts
+++ b/tools/perspective-test/src/js/models/column_settings.ts
@@ -45,10 +45,10 @@ export class ColumnSettingsSidebar {
}
async openTab(name: string) {
- let locator = this.tabTitle.filter({ hasText: name });
+ let locator = this.container.locator("#" + name);
await locator.click({ timeout: 1000 });
await this.container
- .locator(".tab.selected", { hasText: name })
+ .locator(`.tab.selected #${name}`)
.waitFor({ timeout: 1000 });
}
diff --git a/tools/perspective-test/src/js/models/settings_panel.ts b/tools/perspective-test/src/js/models/settings_panel.ts
index 207fedc4d4..0a768cda39 100644
--- a/tools/perspective-test/src/js/models/settings_panel.ts
+++ b/tools/perspective-test/src/js/models/settings_panel.ts
@@ -210,7 +210,7 @@ export class SettingsPanel {
*/
async selectPlugin(name: string) {
await this.pluginSelector.click();
- await this.pluginSelector.getByText(name).click();
+ await this.pluginSelector.locator(`[data-plugin="${name}"]`).click();
}
}