diff --git a/src/components/country-datalist.ts b/src/components/country-datalist.ts
deleted file mode 100644
index 7692e58c0c..0000000000
--- a/src/components/country-datalist.ts
+++ /dev/null
@@ -1,286 +0,0 @@
-import memoizeOne from "memoize-one";
-import { caseInsensitiveStringCompare } from "../common/string/compare";
-
-export const COUNTRIES = [
- "AD",
- "AE",
- "AF",
- "AG",
- "AI",
- "AL",
- "AM",
- "AO",
- "AQ",
- "AR",
- "AS",
- "AT",
- "AU",
- "AW",
- "AX",
- "AZ",
- "BA",
- "BB",
- "BD",
- "BE",
- "BF",
- "BG",
- "BH",
- "BI",
- "BJ",
- "BL",
- "BM",
- "BN",
- "BO",
- "BQ",
- "BR",
- "BS",
- "BT",
- "BV",
- "BW",
- "BY",
- "BZ",
- "CA",
- "CC",
- "CD",
- "CF",
- "CG",
- "CH",
- "CI",
- "CK",
- "CL",
- "CM",
- "CN",
- "CO",
- "CR",
- "CU",
- "CV",
- "CW",
- "CX",
- "CY",
- "CZ",
- "DE",
- "DJ",
- "DK",
- "DM",
- "DO",
- "DZ",
- "EC",
- "EE",
- "EG",
- "EH",
- "ER",
- "ES",
- "ET",
- "FI",
- "FJ",
- "FK",
- "FM",
- "FO",
- "FR",
- "GA",
- "GB",
- "GD",
- "GE",
- "GF",
- "GG",
- "GH",
- "GI",
- "GL",
- "GM",
- "GN",
- "GP",
- "GQ",
- "GR",
- "GS",
- "GT",
- "GU",
- "GW",
- "GY",
- "HK",
- "HM",
- "HN",
- "HR",
- "HT",
- "HU",
- "ID",
- "IE",
- "IL",
- "IM",
- "IN",
- "IO",
- "IQ",
- "IR",
- "IS",
- "IT",
- "JE",
- "JM",
- "JO",
- "JP",
- "KE",
- "KG",
- "KH",
- "KI",
- "KM",
- "KN",
- "KP",
- "KR",
- "KW",
- "KY",
- "KZ",
- "LA",
- "LB",
- "LC",
- "LI",
- "LK",
- "LR",
- "LS",
- "LT",
- "LU",
- "LV",
- "LY",
- "MA",
- "MC",
- "MD",
- "ME",
- "MF",
- "MG",
- "MH",
- "MK",
- "ML",
- "MM",
- "MN",
- "MO",
- "MP",
- "MQ",
- "MR",
- "MS",
- "MT",
- "MU",
- "MV",
- "MW",
- "MX",
- "MY",
- "MZ",
- "NA",
- "NC",
- "NE",
- "NF",
- "NG",
- "NI",
- "NL",
- "NO",
- "NP",
- "NR",
- "NU",
- "NZ",
- "OM",
- "PA",
- "PE",
- "PF",
- "PG",
- "PH",
- "PK",
- "PL",
- "PM",
- "PN",
- "PR",
- "PS",
- "PT",
- "PW",
- "PY",
- "QA",
- "RE",
- "RO",
- "RS",
- "RU",
- "RW",
- "SA",
- "SB",
- "SC",
- "SD",
- "SE",
- "SG",
- "SH",
- "SI",
- "SJ",
- "SK",
- "SL",
- "SM",
- "SN",
- "SO",
- "SR",
- "SS",
- "ST",
- "SV",
- "SX",
- "SY",
- "SZ",
- "TC",
- "TD",
- "TF",
- "TG",
- "TH",
- "TJ",
- "TK",
- "TL",
- "TM",
- "TN",
- "TO",
- "TR",
- "TT",
- "TV",
- "TW",
- "TZ",
- "UA",
- "UG",
- "UM",
- "US",
- "UY",
- "UZ",
- "VA",
- "VC",
- "VE",
- "VG",
- "VI",
- "VN",
- "VU",
- "WF",
- "WS",
- "YE",
- "YT",
- "ZA",
- "ZM",
- "ZW",
-];
-
-export const getCountryOptions = memoizeOne((language?: string) => {
- const countryDisplayNames =
- Intl && "DisplayNames" in Intl
- ? new Intl.DisplayNames(language, {
- type: "region",
- fallback: "code",
- })
- : undefined;
-
- const options = COUNTRIES.map((country) => ({
- value: country,
- label: countryDisplayNames ? countryDisplayNames.of(country)! : country,
- }));
- options.sort((a, b) =>
- caseInsensitiveStringCompare(a.label, b.label, language)
- );
- return options;
-});
-
-export const createCountryListEl = (language?: string) => {
- const list = document.createElement("datalist");
- list.id = "countries";
- const options = getCountryOptions(language);
- for (const country of options) {
- const option = document.createElement("option");
- option.value = country.value;
- option.innerText = country.label;
- list.appendChild(option);
- }
- return list;
-};
diff --git a/src/components/currency-datalist.ts b/src/components/currency-datalist.ts
deleted file mode 100644
index ef29faf56c..0000000000
--- a/src/components/currency-datalist.ts
+++ /dev/null
@@ -1,192 +0,0 @@
-import memoizeOne from "memoize-one";
-import { caseInsensitiveStringCompare } from "../common/string/compare";
-
-export const CURRENCIES = [
- "AED",
- "AFN",
- "ALL",
- "AMD",
- "ANG",
- "AOA",
- "ARS",
- "AUD",
- "AWG",
- "AZN",
- "BAM",
- "BBD",
- "BDT",
- "BGN",
- "BHD",
- "BIF",
- "BMD",
- "BND",
- "BOB",
- "BRL",
- "BSD",
- "BTN",
- "BWP",
- "BYN",
- "BYR",
- "BZD",
- "CAD",
- "CDF",
- "CHF",
- "CLP",
- "CNY",
- "COP",
- "CRC",
- "CUP",
- "CVE",
- "CZK",
- "DJF",
- "DKK",
- "DOP",
- "DZD",
- "EGP",
- "ERN",
- "ETB",
- "EUR",
- "FJD",
- "FKP",
- "GBP",
- "GEL",
- "GHS",
- "GIP",
- "GMD",
- "GNF",
- "GTQ",
- "GYD",
- "HKD",
- "HNL",
- "HRK",
- "HTG",
- "HUF",
- "IDR",
- "ILS",
- "INR",
- "IQD",
- "IRR",
- "ISK",
- "JMD",
- "JOD",
- "JPY",
- "KES",
- "KGS",
- "KHR",
- "KMF",
- "KPW",
- "KRW",
- "KWD",
- "KYD",
- "KZT",
- "LAK",
- "LBP",
- "LKR",
- "LRD",
- "LSL",
- "LTL",
- "LYD",
- "MAD",
- "MDL",
- "MGA",
- "MKD",
- "MMK",
- "MNT",
- "MOP",
- "MRO",
- "MUR",
- "MVR",
- "MWK",
- "MXN",
- "MYR",
- "MZN",
- "NAD",
- "NGN",
- "NIO",
- "NOK",
- "NPR",
- "NZD",
- "OMR",
- "PAB",
- "PEN",
- "PGK",
- "PHP",
- "PKR",
- "PLN",
- "PYG",
- "QAR",
- "RON",
- "RSD",
- "RUB",
- "RWF",
- "SAR",
- "SBD",
- "SCR",
- "SDG",
- "SEK",
- "SGD",
- "SHP",
- "SLL",
- "SOS",
- "SRD",
- "SSP",
- "STD",
- "SYP",
- "SZL",
- "THB",
- "TJS",
- "TMT",
- "TND",
- "TOP",
- "TRY",
- "TTD",
- "TWD",
- "TZS",
- "UAH",
- "UGX",
- "USD",
- "UYU",
- "UZS",
- "VEF",
- "VND",
- "VUV",
- "WST",
- "XAF",
- "XCD",
- "XOF",
- "XPF",
- "YER",
- "ZAR",
- "ZMW",
- "ZWL",
-];
-
-export const getCurrencyOptions = memoizeOne((language?: string) => {
- const currencyDisplayNames =
- Intl && "DisplayNames" in Intl
- ? new Intl.DisplayNames(language, {
- type: "currency",
- fallback: "code",
- })
- : undefined;
- const options = CURRENCIES.map((currency) => ({
- value: currency,
- label: currencyDisplayNames ? currencyDisplayNames.of(currency)! : currency,
- }));
- options.sort((a, b) =>
- caseInsensitiveStringCompare(a.label, b.label, language)
- );
- return options;
-});
-
-export const createCurrencyListEl = (language: string) => {
- const list = document.createElement("datalist");
- list.id = "currencies";
- for (const currency of getCurrencyOptions(language)) {
- const option = document.createElement("option");
- option.value = currency.value;
- option.innerText = currency.label;
- list.appendChild(option);
- }
- return list;
-};
diff --git a/src/components/ha-country-picker.ts b/src/components/ha-country-picker.ts
new file mode 100644
index 0000000000..5fff71bdfa
--- /dev/null
+++ b/src/components/ha-country-picker.ts
@@ -0,0 +1,340 @@
+import { css, CSSResultGroup, html, LitElement } from "lit";
+import { customElement, property } from "lit/decorators";
+import memoizeOne from "memoize-one";
+import { fireEvent } from "../common/dom/fire_event";
+import { stopPropagation } from "../common/dom/stop_propagation";
+import { caseInsensitiveStringCompare } from "../common/string/compare";
+import "../resources/intl-polyfill";
+import "./ha-list-item";
+import "./ha-select";
+import type { HaSelect } from "./ha-select";
+
+const COUNTRIES = [
+ "AD",
+ "AE",
+ "AF",
+ "AG",
+ "AI",
+ "AL",
+ "AM",
+ "AO",
+ "AQ",
+ "AR",
+ "AS",
+ "AT",
+ "AU",
+ "AW",
+ "AX",
+ "AZ",
+ "BA",
+ "BB",
+ "BD",
+ "BE",
+ "BF",
+ "BG",
+ "BH",
+ "BI",
+ "BJ",
+ "BL",
+ "BM",
+ "BN",
+ "BO",
+ "BQ",
+ "BR",
+ "BS",
+ "BT",
+ "BV",
+ "BW",
+ "BY",
+ "BZ",
+ "CA",
+ "CC",
+ "CD",
+ "CF",
+ "CG",
+ "CH",
+ "CI",
+ "CK",
+ "CL",
+ "CM",
+ "CN",
+ "CO",
+ "CR",
+ "CU",
+ "CV",
+ "CW",
+ "CX",
+ "CY",
+ "CZ",
+ "DE",
+ "DJ",
+ "DK",
+ "DM",
+ "DO",
+ "DZ",
+ "EC",
+ "EE",
+ "EG",
+ "EH",
+ "ER",
+ "ES",
+ "ET",
+ "FI",
+ "FJ",
+ "FK",
+ "FM",
+ "FO",
+ "FR",
+ "GA",
+ "GB",
+ "GD",
+ "GE",
+ "GF",
+ "GG",
+ "GH",
+ "GI",
+ "GL",
+ "GM",
+ "GN",
+ "GP",
+ "GQ",
+ "GR",
+ "GS",
+ "GT",
+ "GU",
+ "GW",
+ "GY",
+ "HK",
+ "HM",
+ "HN",
+ "HR",
+ "HT",
+ "HU",
+ "ID",
+ "IE",
+ "IL",
+ "IM",
+ "IN",
+ "IO",
+ "IQ",
+ "IR",
+ "IS",
+ "IT",
+ "JE",
+ "JM",
+ "JO",
+ "JP",
+ "KE",
+ "KG",
+ "KH",
+ "KI",
+ "KM",
+ "KN",
+ "KP",
+ "KR",
+ "KW",
+ "KY",
+ "KZ",
+ "LA",
+ "LB",
+ "LC",
+ "LI",
+ "LK",
+ "LR",
+ "LS",
+ "LT",
+ "LU",
+ "LV",
+ "LY",
+ "MA",
+ "MC",
+ "MD",
+ "ME",
+ "MF",
+ "MG",
+ "MH",
+ "MK",
+ "ML",
+ "MM",
+ "MN",
+ "MO",
+ "MP",
+ "MQ",
+ "MR",
+ "MS",
+ "MT",
+ "MU",
+ "MV",
+ "MW",
+ "MX",
+ "MY",
+ "MZ",
+ "NA",
+ "NC",
+ "NE",
+ "NF",
+ "NG",
+ "NI",
+ "NL",
+ "NO",
+ "NP",
+ "NR",
+ "NU",
+ "NZ",
+ "OM",
+ "PA",
+ "PE",
+ "PF",
+ "PG",
+ "PH",
+ "PK",
+ "PL",
+ "PM",
+ "PN",
+ "PR",
+ "PS",
+ "PT",
+ "PW",
+ "PY",
+ "QA",
+ "RE",
+ "RO",
+ "RS",
+ "RU",
+ "RW",
+ "SA",
+ "SB",
+ "SC",
+ "SD",
+ "SE",
+ "SG",
+ "SH",
+ "SI",
+ "SJ",
+ "SK",
+ "SL",
+ "SM",
+ "SN",
+ "SO",
+ "SR",
+ "SS",
+ "ST",
+ "SV",
+ "SX",
+ "SY",
+ "SZ",
+ "TC",
+ "TD",
+ "TF",
+ "TG",
+ "TH",
+ "TJ",
+ "TK",
+ "TL",
+ "TM",
+ "TN",
+ "TO",
+ "TR",
+ "TT",
+ "TV",
+ "TW",
+ "TZ",
+ "UA",
+ "UG",
+ "UM",
+ "US",
+ "UY",
+ "UZ",
+ "VA",
+ "VC",
+ "VE",
+ "VG",
+ "VI",
+ "VN",
+ "VU",
+ "WF",
+ "WS",
+ "YE",
+ "YT",
+ "ZA",
+ "ZM",
+ "ZW",
+];
+
+@customElement("ha-country-picker")
+export class HaCountryPicker extends LitElement {
+ @property() public language = "en";
+
+ @property() public value?: string;
+
+ @property() public label?: string;
+
+ @property({ type: Boolean }) public required = false;
+
+ @property({ type: Boolean, reflect: true }) public disabled = false;
+
+ private _getOptions = memoizeOne((language?: string) => {
+ const countryDisplayNames =
+ Intl && "DisplayNames" in Intl
+ ? new Intl.DisplayNames(language, {
+ type: "region",
+ fallback: "code",
+ })
+ : undefined;
+
+ const options = COUNTRIES.map((country) => ({
+ value: country,
+ label: countryDisplayNames ? countryDisplayNames.of(country)! : country,
+ }));
+ options.sort((a, b) =>
+ caseInsensitiveStringCompare(a.label, b.label, language)
+ );
+ return options;
+ });
+
+ protected render() {
+ const options = this._getOptions(this.language);
+
+ return html`
+
+ ${options.map(
+ (option) => html`
+ ${option.label}
+ `
+ )}
+
+ `;
+ }
+
+ static get styles(): CSSResultGroup {
+ return css`
+ ha-select {
+ width: 100%;
+ }
+ `;
+ }
+
+ private _changed(ev): void {
+ const target = ev.target as HaSelect;
+ if (target.value === "" || target.value === this.value) {
+ return;
+ }
+ this.value = target.value;
+ fireEvent(this, "value-changed", { value: this.value });
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-country-picker": HaCountryPicker;
+ }
+}
diff --git a/src/components/ha-currency-picker.ts b/src/components/ha-currency-picker.ts
new file mode 100644
index 0000000000..10a3f90012
--- /dev/null
+++ b/src/components/ha-currency-picker.ts
@@ -0,0 +1,256 @@
+import { css, CSSResultGroup, html, LitElement } from "lit";
+import { customElement, property } from "lit/decorators";
+import memoizeOne from "memoize-one";
+import { fireEvent } from "../common/dom/fire_event";
+import { stopPropagation } from "../common/dom/stop_propagation";
+import { caseInsensitiveStringCompare } from "../common/string/compare";
+import "../resources/intl-polyfill";
+import "./ha-list-item";
+import "./ha-select";
+import type { HaSelect } from "./ha-select";
+
+const CURRENCIES = [
+ "AED",
+ "AFN",
+ "ALL",
+ "AMD",
+ "ANG",
+ "AOA",
+ "ARS",
+ "AUD",
+ "AWG",
+ "AZN",
+ "BAM",
+ "BBD",
+ "BDT",
+ "BGN",
+ "BHD",
+ "BIF",
+ "BMD",
+ "BND",
+ "BOB",
+ "BRL",
+ "BSD",
+ "BTN",
+ "BWP",
+ "BYN",
+ "BYR",
+ "BZD",
+ "CAD",
+ "CDF",
+ "CHF",
+ "CLP",
+ "CNY",
+ "COP",
+ "CRC",
+ "CUP",
+ "CVE",
+ "CZK",
+ "DJF",
+ "DKK",
+ "DOP",
+ "DZD",
+ "EGP",
+ "ERN",
+ "ETB",
+ "EUR",
+ "FJD",
+ "FKP",
+ "GBP",
+ "GEL",
+ "GHS",
+ "GIP",
+ "GMD",
+ "GNF",
+ "GTQ",
+ "GYD",
+ "HKD",
+ "HNL",
+ "HRK",
+ "HTG",
+ "HUF",
+ "IDR",
+ "ILS",
+ "INR",
+ "IQD",
+ "IRR",
+ "ISK",
+ "JMD",
+ "JOD",
+ "JPY",
+ "KES",
+ "KGS",
+ "KHR",
+ "KMF",
+ "KPW",
+ "KRW",
+ "KWD",
+ "KYD",
+ "KZT",
+ "LAK",
+ "LBP",
+ "LKR",
+ "LRD",
+ "LSL",
+ "LTL",
+ "LYD",
+ "MAD",
+ "MDL",
+ "MGA",
+ "MKD",
+ "MMK",
+ "MNT",
+ "MOP",
+ "MRO",
+ "MUR",
+ "MVR",
+ "MWK",
+ "MXN",
+ "MYR",
+ "MZN",
+ "NAD",
+ "NGN",
+ "NIO",
+ "NOK",
+ "NPR",
+ "NZD",
+ "OMR",
+ "PAB",
+ "PEN",
+ "PGK",
+ "PHP",
+ "PKR",
+ "PLN",
+ "PYG",
+ "QAR",
+ "RON",
+ "RSD",
+ "RUB",
+ "RWF",
+ "SAR",
+ "SBD",
+ "SCR",
+ "SDG",
+ "SEK",
+ "SGD",
+ "SHP",
+ "SLL",
+ "SOS",
+ "SRD",
+ "SSP",
+ "STD",
+ "SYP",
+ "SZL",
+ "THB",
+ "TJS",
+ "TMT",
+ "TND",
+ "TOP",
+ "TRY",
+ "TTD",
+ "TWD",
+ "TZS",
+ "UAH",
+ "UGX",
+ "USD",
+ "UYU",
+ "UZS",
+ "VEF",
+ "VND",
+ "VUV",
+ "WST",
+ "XAF",
+ "XCD",
+ "XOF",
+ "XPF",
+ "YER",
+ "ZAR",
+ "ZMW",
+ "ZWL",
+];
+
+const curSymbol = (currency: string, locale?: string) =>
+ Intl && "NumberFormat" in Intl
+ ? new Intl.NumberFormat(locale, { style: "currency", currency })
+ .formatToParts(1)
+ .find((x) => x.type === "currency")?.value
+ : currency;
+
+@customElement("ha-currency-picker")
+export class HaCurrencyPicker extends LitElement {
+ @property() public language = "en";
+
+ @property() public value?: string;
+
+ @property() public label?: string;
+
+ @property({ type: Boolean }) public required = false;
+
+ @property({ type: Boolean, reflect: true }) public disabled = false;
+
+ private _getOptions = memoizeOne((language?: string) => {
+ const currencyDisplayNames =
+ Intl && "DisplayNames" in Intl
+ ? new Intl.DisplayNames(language, {
+ type: "currency",
+ fallback: "code",
+ })
+ : undefined;
+ const options = CURRENCIES.map((currency) => ({
+ value: currency,
+ label: `${
+ currencyDisplayNames ? currencyDisplayNames.of(currency)! : currency
+ } (${curSymbol(currency, language)})`,
+ }));
+ options.sort((a, b) =>
+ caseInsensitiveStringCompare(a.label, b.label, language)
+ );
+ return options;
+ });
+
+ protected render() {
+ const options = this._getOptions(this.language);
+
+ return html`
+
+ ${options.map(
+ (option) => html`
+ ${option.label}
+ `
+ )}
+
+ `;
+ }
+
+ static get styles(): CSSResultGroup {
+ return css`
+ ha-select {
+ width: 100%;
+ }
+ `;
+ }
+
+ private _changed(ev): void {
+ const target = ev.target as HaSelect;
+ if (target.value === "" || target.value === this.value) {
+ return;
+ }
+ this.value = target.value;
+ fireEvent(this, "value-changed", { value: this.value });
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-currency-picker": HaCurrencyPicker;
+ }
+}
diff --git a/src/components/ha-language-picker.ts b/src/components/ha-language-picker.ts
index 618709c980..5d1ece061b 100644
--- a/src/components/ha-language-picker.ts
+++ b/src/components/ha-language-picker.ts
@@ -6,6 +6,7 @@ import { stopPropagation } from "../common/dom/stop_propagation";
import { formatLanguageCode } from "../common/language/format_language";
import { caseInsensitiveStringCompare } from "../common/string/compare";
import { FrontendLocaleData } from "../data/translation";
+import "../resources/intl-polyfill";
import { HomeAssistant } from "../types";
import "./ha-list-item";
import "./ha-select";
diff --git a/src/components/ha-timezone-picker.ts b/src/components/ha-timezone-picker.ts
new file mode 100644
index 0000000000..8388f8ac8c
--- /dev/null
+++ b/src/components/ha-timezone-picker.ts
@@ -0,0 +1,62 @@
+import timezones from "google-timezones-json";
+import { css, CSSResultGroup, html, LitElement } from "lit";
+import { customElement, property } from "lit/decorators";
+import { fireEvent } from "../common/dom/fire_event";
+import { stopPropagation } from "../common/dom/stop_propagation";
+import "./ha-list-item";
+import "./ha-select";
+import type { HaSelect } from "./ha-select";
+
+@customElement("ha-timezone-picker")
+export class HaTimeZonePicker extends LitElement {
+ @property() public value?: string;
+
+ @property() public label?: string;
+
+ @property({ type: Boolean }) public required = false;
+
+ @property({ type: Boolean, reflect: true }) public disabled = false;
+
+ protected render() {
+ return html`
+
+ ${Object.entries(timezones).map(
+ ([key, value]) =>
+ html`${value}`
+ )}
+
+ `;
+ }
+
+ static get styles(): CSSResultGroup {
+ return css`
+ ha-select {
+ width: 100%;
+ }
+ `;
+ }
+
+ private _changed(ev): void {
+ const target = ev.target as HaSelect;
+ if (target.value === "" || target.value === this.value) {
+ return;
+ }
+ this.value = target.value;
+ fireEvent(this, "value-changed", { value: this.value });
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-timezone-picker": HaTimeZonePicker;
+ }
+}
diff --git a/src/data/currency.ts b/src/data/currency.ts
deleted file mode 100644
index d8ddf7933e..0000000000
--- a/src/data/currency.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export const SYMBOL_TO_ISO = {
- $: "USD",
- "€": "EUR",
- "¥": "JPY",
- "£": "GBP",
- "₽": "RUB",
- "₹": "INR",
-};
diff --git a/src/onboarding/onboarding-core-config.ts b/src/onboarding/onboarding-core-config.ts
index 80a652ab94..9bf3be1ddb 100644
--- a/src/onboarding/onboarding-core-config.ts
+++ b/src/onboarding/onboarding-core-config.ts
@@ -11,29 +11,28 @@ import { customElement, property, query, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../common/dom/fire_event";
import type { LocalizeFunc } from "../common/translations/localize";
-import { createCountryListEl } from "../components/country-datalist";
-import { createCurrencyListEl } from "../components/currency-datalist";
import "../components/ha-alert";
+import "../components/ha-country-picker";
+import "../components/ha-currency-picker";
import "../components/ha-formfield";
+import "../components/ha-language-picker";
import "../components/ha-radio";
import type { HaRadio } from "../components/ha-radio";
import "../components/ha-textfield";
import type { HaTextField } from "../components/ha-textfield";
-import { createLanguageListEl } from "../components/language-datalist";
+import "../components/ha-timezone-picker";
import "../components/map/ha-locations-editor";
import type {
HaLocationsEditor,
MarkerLocation,
} from "../components/map/ha-locations-editor";
-import { createTimezoneListEl } from "../components/timezone-datalist";
import {
ConfigUpdateValues,
detectCoreConfig,
saveCoreConfig,
} from "../data/core";
-import { SYMBOL_TO_ISO } from "../data/currency";
import { onboardCoreConfigStep } from "../data/onboarding";
-import type { ValueChangedEvent, HomeAssistant } from "../types";
+import type { HomeAssistant, ValueChangedEvent } from "../types";
import { getLocalLanguage } from "../util/common-translation";
const amsterdam: [number, number] = [52.3731339, 4.8903147];
@@ -58,9 +57,11 @@ class OnboardingCoreConfig extends LitElement {
@state() private _currency?: ConfigUpdateValues["currency"];
- @state() private _timeZone?: string;
+ @state() private _timeZone? =
+ Intl.DateTimeFormat?.().resolvedOptions?.().timeZone;
- @state() private _language?: ConfigUpdateValues["language"];
+ @state() private _language: ConfigUpdateValues["language"] =
+ getLocalLanguage();
@state() private _country?: ConfigUpdateValues["country"];
@@ -127,45 +128,50 @@ class OnboardingCoreConfig extends LitElement {
-
-
+
+
+ .disabled=${this._working}
+ @value-changed=${this._handleValueChanged}
+ >
+
-
+
+
-
-
+
+
@@ -279,45 +286,6 @@ class OnboardingCoreConfig extends LitElement {
this._save(ev);
}
});
- const tzInput = this.renderRoot.querySelector(
- "[name=timeZone]"
- ) as HaTextField;
- tzInput.updateComplete.then(() => {
- tzInput.renderRoot.appendChild(createTimezoneListEl());
- tzInput.formElement.setAttribute("list", "timezones");
- });
-
- const curInput = this.renderRoot.querySelector(
- "[name=currency]"
- ) as HaTextField;
- curInput.updateComplete.then(() => {
- curInput.renderRoot.appendChild(
- createCurrencyListEl(this.hass.locale.language)
- );
- curInput.formElement.setAttribute("list", "currencies");
- });
-
- const countryInput = this.renderRoot.querySelector(
- "[name=country]"
- ) as HaTextField;
- countryInput.updateComplete.then(() => {
- countryInput.renderRoot.appendChild(
- createCountryListEl(this.hass.locale.language)
- );
-
- countryInput.formElement.setAttribute("list", "countries");
- });
-
- const langInput = this.renderRoot.querySelector(
- "[name=language]"
- ) as HaTextField;
- langInput.updateComplete.then(() => {
- langInput.renderRoot.appendChild(createLanguageListEl(this.hass));
- langInput.renderRoot
- .querySelector("#label")
- ?.classList.add("mdc-floating-label--required");
- langInput.formElement.setAttribute("list", "languages");
- });
}
private get _nameValue() {
@@ -367,18 +335,14 @@ class OnboardingCoreConfig extends LitElement {
]
);
+ private _handleValueChanged(ev) {
+ const target = ev.currentTarget;
+ this[`_${target.getAttribute("name")}`] = ev.detail.value;
+ }
+
private _handleChange(ev: ValueChangedEvent) {
const target = ev.currentTarget as HaTextField;
-
- let value = target.value;
-
- if (target.name === "currency" && value) {
- if (value in SYMBOL_TO_ISO) {
- value = SYMBOL_TO_ISO[value];
- }
- }
-
- this[`_${target.name}`] = value;
+ this[`_${target.name}`] = target.value;
}
private _locationChanged(ev) {
@@ -465,6 +429,7 @@ class OnboardingCoreConfig extends LitElement {
flex-direction: row;
margin: 0 -8px;
align-items: center;
+ --ha-select-min-width: 100px;
}
.secondary {
diff --git a/src/panels/config/core/ha-config-section-general.ts b/src/panels/config/core/ha-config-section-general.ts
index 0d6e95dbc7..59899d0984 100644
--- a/src/panels/config/core/ha-config-section-general.ts
+++ b/src/panels/config/core/ha-config-section-general.ts
@@ -1,5 +1,4 @@
import "@material/mwc-list/mwc-list-item";
-import timezones from "google-timezones-json";
import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
@@ -8,12 +7,12 @@ import { stopPropagation } from "../../../common/dom/stop_propagation";
import { navigate } from "../../../common/navigate";
import "../../../components/buttons/ha-progress-button";
import type { HaProgressButton } from "../../../components/buttons/ha-progress-button";
-import { getCountryOptions } from "../../../components/country-datalist";
-import { getCurrencyOptions } from "../../../components/currency-datalist";
import "../../../components/ha-alert";
import "../../../components/ha-card";
import "../../../components/ha-checkbox";
import type { HaCheckbox } from "../../../components/ha-checkbox";
+import "../../../components/ha-country-picker";
+import "../../../components/ha-currency-picker";
import "../../../components/ha-formfield";
import "../../../components/ha-language-picker";
import "../../../components/ha-radio";
@@ -21,10 +20,10 @@ import type { HaRadio } from "../../../components/ha-radio";
import "../../../components/ha-select";
import "../../../components/ha-settings-row";
import "../../../components/ha-textfield";
+import "../../../components/ha-timezone-picker";
import "../../../components/map/ha-locations-editor";
import type { MarkerLocation } from "../../../components/map/ha-locations-editor";
import { ConfigUpdateValues, saveCoreConfig } from "../../../data/core";
-import { SYMBOL_TO_ISO } from "../../../data/currency";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import "../../../layouts/hass-subpage";
import { haStyle } from "../../../resources/styles";
@@ -94,25 +93,16 @@ class HaConfigSectionGeneral extends LitElement {
.value=${this._name}
@change=${this._handleChange}
>
-
- ${Object.keys(timezones).map(
- (tz) =>
- html`${timezones[tz]}`
- )}
-
+
-
- ${getCurrencyOptions(this.hass.locale.language).map(
- ({ value, label }) =>
- html`
- ${label}
- `
- )}
+
-
- ${getCountryOptions(this.hass.locale.language).map(
- ({ value, label }) =>
- html`
- ${label}
- `
- )}
+ @value-changed=${this._handleValueChanged}
+ >
@@ -319,26 +293,22 @@ class HaConfigSectionGeneral extends LitElement {
this._country = this.hass.config.country;
this._language = this.hass.config.language;
this._elevation = this.hass.config.elevation;
- this._timeZone = this.hass.config.time_zone || "Etc/GMT";
+ this._timeZone =
+ this.hass.config.time_zone ||
+ Intl.DateTimeFormat?.().resolvedOptions?.().timeZone ||
+ "Etc/GMT";
this._name = this.hass.config.location_name;
this._updateUnits = true;
}
- private _handleLanguageChange(ev) {
- this._language = ev.detail.value;
+ private _handleValueChanged(ev) {
+ const target = ev.currentTarget;
+ this[`_${target.name}`] = ev.detail.value;
}
private _handleChange(ev) {
const target = ev.currentTarget;
- let value = target.value;
-
- if (target.name === "currency" && value) {
- if (value in SYMBOL_TO_ISO) {
- value = SYMBOL_TO_ISO[value];
- }
- }
-
- this[`_${target.name}`] = value;
+ this[`_${target.name}`] = target.value;
}
private _unitSystemChanged(ev: CustomEvent) {
diff --git a/src/resources/intl-polyfill.ts b/src/resources/intl-polyfill.ts
index ec57044ecb..8b09aea77a 100644
--- a/src/resources/intl-polyfill.ts
+++ b/src/resources/intl-polyfill.ts
@@ -1,8 +1,8 @@
-import { shouldPolyfill as shouldPolyfillDateTime } from "@formatjs/intl-datetimeformat/lib/should-polyfill";
-import { shouldPolyfill as shouldPolyfillDisplayName } from "@formatjs/intl-displaynames/lib/should-polyfill";
-import { shouldPolyfill as shouldPolyfillLocale } from "@formatjs/intl-locale/lib/should-polyfill";
-import { shouldPolyfill as shouldPolyfillPluralRules } from "@formatjs/intl-pluralrules/lib/should-polyfill";
-import { shouldPolyfill as shouldPolyfillRelativeTime } from "@formatjs/intl-relativetimeformat/lib/should-polyfill";
+import { shouldPolyfill as shouldPolyfillDateTime } from "@formatjs/intl-datetimeformat/should-polyfill";
+import { shouldPolyfill as shouldPolyfillDisplayName } from "@formatjs/intl-displaynames/should-polyfill";
+import { shouldPolyfill as shouldPolyfillLocale } from "@formatjs/intl-locale/should-polyfill";
+import { shouldPolyfill as shouldPolyfillPluralRules } from "@formatjs/intl-pluralrules/should-polyfill";
+import { shouldPolyfill as shouldPolyfillRelativeTime } from "@formatjs/intl-relativetimeformat/should-polyfill";
import { getLocalLanguage } from "../util/common-translation";
import { polyfillLocaleData } from "./locale-data-polyfill";
@@ -14,11 +14,7 @@ const polyfillIntl = async () => {
await import("@formatjs/intl-locale/polyfill-force");
}
if (shouldPolyfillPluralRules(locale)) {
- polyfills.push(
- import("@formatjs/intl-pluralrules/polyfill-force").then(
- () => import("@formatjs/intl-pluralrules/locale-data/en")
- )
- );
+ polyfills.push(import("@formatjs/intl-pluralrules/polyfill-force"));
}
if (shouldPolyfillRelativeTime(locale)) {
polyfills.push(import("@formatjs/intl-relativetimeformat/polyfill-force"));
@@ -31,11 +27,10 @@ const polyfillIntl = async () => {
);
}
if (shouldPolyfillDisplayName(locale)) {
- polyfills.push(
- import("@formatjs/intl-displaynames/polyfill-force").then(
- () => import("@formatjs/intl-displaynames/locale-data/en")
- )
- );
+ polyfills.push(import("@formatjs/intl-displaynames/polyfill-force"));
+ }
+ if (polyfills.length === 0) {
+ return;
}
await Promise.all(polyfills).then(() =>
// Load the default language