Use browser default time and number formatting with polyfills if needed (#9481)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
parent
d7f00df391
commit
1bccbd4173
|
@ -12,7 +12,7 @@ on:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
NODE_VERSION: 14
|
NODE_VERSION: 14
|
||||||
NODE_OPTIONS: --max_old_space_size=4096
|
NODE_OPTIONS: --max_old_space_size=6144
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
|
@ -53,8 +53,8 @@ jobs:
|
||||||
run: yarn install
|
run: yarn install
|
||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
- name: Run Mocha
|
- name: Run Tests
|
||||||
run: yarn run mocha
|
run: yarn run test
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [lint, test]
|
needs: [lint, test]
|
||||||
|
|
|
@ -7,7 +7,7 @@ on:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
NODE_VERSION: 14
|
NODE_VERSION: 14
|
||||||
NODE_OPTIONS: --max_old_space_size=4096
|
NODE_OPTIONS: --max_old_space_size=6144
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
deploy:
|
deploy:
|
||||||
|
|
|
@ -8,7 +8,7 @@ on:
|
||||||
env:
|
env:
|
||||||
PYTHON_VERSION: 3.8
|
PYTHON_VERSION: 3.8
|
||||||
NODE_VERSION: 14
|
NODE_VERSION: 14
|
||||||
NODE_OPTIONS: --max_old_space_size=4096
|
NODE_OPTIONS: --max_old_space_size=6144
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
require: "test-mocha/testconf.js",
|
|
||||||
timeout: 10000,
|
|
||||||
};
|
|
|
@ -82,6 +82,7 @@ module.exports.babelOptions = ({ latestBuild }) => ({
|
||||||
// Only support the syntax, Webpack will handle it.
|
// Only support the syntax, Webpack will handle it.
|
||||||
"@babel/plugin-syntax-import-meta",
|
"@babel/plugin-syntax-import-meta",
|
||||||
"@babel/plugin-syntax-dynamic-import",
|
"@babel/plugin-syntax-dynamic-import",
|
||||||
|
"@babel/plugin-syntax-top-level-await",
|
||||||
"@babel/plugin-proposal-optional-chaining",
|
"@babel/plugin-proposal-optional-chaining",
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator",
|
"@babel/plugin-proposal-nullish-coalescing-operator",
|
||||||
["@babel/plugin-proposal-decorators", { decoratorsBeforeExport: true }],
|
["@babel/plugin-proposal-decorators", { decoratorsBeforeExport: true }],
|
||||||
|
|
|
@ -6,6 +6,7 @@ const { WebpackManifestPlugin } = require("webpack-manifest-plugin");
|
||||||
const paths = require("./paths.js");
|
const paths = require("./paths.js");
|
||||||
const bundle = require("./bundle.js");
|
const bundle = require("./bundle.js");
|
||||||
const log = require("fancy-log");
|
const log = require("fancy-log");
|
||||||
|
const WebpackBar = require("webpackbar");
|
||||||
|
|
||||||
class LogStartCompilePlugin {
|
class LogStartCompilePlugin {
|
||||||
ignoredFirst = false;
|
ignoredFirst = false;
|
||||||
|
@ -74,6 +75,7 @@ const createWebpackConfig = ({
|
||||||
chunkIds: isProdBuild && !isStatsBuild ? "deterministic" : "named",
|
chunkIds: isProdBuild && !isStatsBuild ? "deterministic" : "named",
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
new WebpackBar({ fancy: !isProdBuild }),
|
||||||
new WebpackManifestPlugin({
|
new WebpackManifestPlugin({
|
||||||
// Only include the JS of entrypoints
|
// Only include the JS of entrypoints
|
||||||
filter: (file) => file.isInitial && !file.name.endsWith(".map"),
|
filter: (file) => file.isInitial && !file.name.endsWith(".map"),
|
||||||
|
@ -149,6 +151,9 @@ const createWebpackConfig = ({
|
||||||
// To silence warning in worker plugin
|
// To silence warning in worker plugin
|
||||||
globalObject: "self",
|
globalObject: "self",
|
||||||
},
|
},
|
||||||
|
experiments: {
|
||||||
|
topLevelAwait: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { customElement, property, query, state } from "lit/decorators";
|
||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { atLeastVersion } from "../../../src/common/config/version";
|
import { atLeastVersion } from "../../../src/common/config/version";
|
||||||
import relativeTime from "../../../src/common/datetime/relative_time";
|
import { relativeTime } from "../../../src/common/datetime/relative_time";
|
||||||
import { HASSDomEvent } from "../../../src/common/dom/fire_event";
|
import { HASSDomEvent } from "../../../src/common/dom/fire_event";
|
||||||
import {
|
import {
|
||||||
DataTableColumnContainer,
|
DataTableColumnContainer,
|
||||||
|
@ -133,7 +133,7 @@ export class HassioBackups extends LitElement {
|
||||||
filterable: true,
|
filterable: true,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
template: (entry: string) =>
|
template: (entry: string) =>
|
||||||
relativeTime(new Date(entry), this.hass.localize),
|
relativeTime(new Date(entry), this.hass.locale),
|
||||||
},
|
},
|
||||||
secondary: {
|
secondary: {
|
||||||
title: "",
|
title: "",
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
[build.environment]
|
[build.environment]
|
||||||
YARN_VERSION = "1.22.11"
|
YARN_VERSION = "1.22.11"
|
||||||
NODE_OPTIONS = "--max_old_space_size=4096"
|
NODE_OPTIONS = "--max_old_space_size=6144"
|
||||||
|
|
26
package.json
26
package.json
|
@ -16,8 +16,7 @@
|
||||||
"lint:lit": "lit-analyzer \"**/src/**/*.ts\" --format markdown --outFile result.md",
|
"lint:lit": "lit-analyzer \"**/src/**/*.ts\" --format markdown --outFile result.md",
|
||||||
"lint": "yarn run lint:eslint && yarn run lint:prettier && yarn run lint:types",
|
"lint": "yarn run lint:eslint && yarn run lint:prettier && yarn run lint:types",
|
||||||
"format": "yarn run format:eslint && yarn run format:prettier",
|
"format": "yarn run format:eslint && yarn run format:prettier",
|
||||||
"mocha": "ts-mocha -p test-mocha/tsconfig.test.json \"test-mocha/**/*.ts\"",
|
"test": "instant-mocha --webpack-config ./test/webpack.config.js --require ./test/setup.js \"test/**/*.ts\""
|
||||||
"test": "yarn run mocha"
|
|
||||||
},
|
},
|
||||||
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
|
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
@ -34,9 +33,13 @@
|
||||||
"@codemirror/stream-parser": "^0.19.1",
|
"@codemirror/stream-parser": "^0.19.1",
|
||||||
"@codemirror/text": "^0.19.2",
|
"@codemirror/text": "^0.19.2",
|
||||||
"@codemirror/view": "^0.19.4",
|
"@codemirror/view": "^0.19.4",
|
||||||
|
"@formatjs/intl-datetimeformat": "^4.2.4",
|
||||||
"@formatjs/intl-getcanonicallocales": "^1.7.3",
|
"@formatjs/intl-getcanonicallocales": "^1.7.3",
|
||||||
"@formatjs/intl-locale": "^2.4.37",
|
"@formatjs/intl-locale": "^2.4.38",
|
||||||
"@formatjs/intl-pluralrules": "^4.1.3",
|
"@formatjs/intl-numberformat": "^7.2.4",
|
||||||
|
"@formatjs/intl-pluralrules": "^4.1.4",
|
||||||
|
"@formatjs/intl-relativetimeformat": "^9.3.1",
|
||||||
|
"@formatjs/intl-utils": "^3.8.4",
|
||||||
"@fullcalendar/common": "5.9.0",
|
"@fullcalendar/common": "5.9.0",
|
||||||
"@fullcalendar/core": "5.9.0",
|
"@fullcalendar/core": "5.9.0",
|
||||||
"@fullcalendar/daygrid": "5.9.0",
|
"@fullcalendar/daygrid": "5.9.0",
|
||||||
|
@ -103,7 +106,6 @@
|
||||||
"date-fns": "^2.23.0",
|
"date-fns": "^2.23.0",
|
||||||
"deep-clone-simple": "^1.1.1",
|
"deep-clone-simple": "^1.1.1",
|
||||||
"deep-freeze": "^0.0.1",
|
"deep-freeze": "^0.0.1",
|
||||||
"fecha": "^4.2.0",
|
|
||||||
"fuse.js": "^6.0.0",
|
"fuse.js": "^6.0.0",
|
||||||
"google-timezones-json": "^1.0.2",
|
"google-timezones-json": "^1.0.2",
|
||||||
"hls.js": "^1.0.10",
|
"hls.js": "^1.0.10",
|
||||||
|
@ -152,6 +154,7 @@
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.14.5",
|
"@babel/plugin-proposal-optional-chaining": "^7.14.5",
|
||||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||||
"@babel/plugin-syntax-import-meta": "^7.10.4",
|
"@babel/plugin-syntax-import-meta": "^7.10.4",
|
||||||
|
"@babel/plugin-syntax-top-level-await": "^7.14.5",
|
||||||
"@babel/preset-env": "^7.14.7",
|
"@babel/preset-env": "^7.14.7",
|
||||||
"@babel/preset-typescript": "^7.14.5",
|
"@babel/preset-typescript": "^7.14.5",
|
||||||
"@koa/cors": "^3.1.0",
|
"@koa/cors": "^3.1.0",
|
||||||
|
@ -197,6 +200,7 @@
|
||||||
"gulp-zopfli-green": "^3.0.1",
|
"gulp-zopfli-green": "^3.0.1",
|
||||||
"html-minifier": "^4.0.0",
|
"html-minifier": "^4.0.0",
|
||||||
"husky": "^1.3.1",
|
"husky": "^1.3.1",
|
||||||
|
"instant-mocha": "^1.3.1",
|
||||||
"lint-staged": "^11.0.1",
|
"lint-staged": "^11.0.1",
|
||||||
"lit-analyzer": "^1.2.1",
|
"lit-analyzer": "^1.2.1",
|
||||||
"lodash.template": "^4.5.0",
|
"lodash.template": "^4.5.0",
|
||||||
|
@ -216,16 +220,16 @@
|
||||||
"sinon": "^11.0.0",
|
"sinon": "^11.0.0",
|
||||||
"source-map-url": "^0.4.0",
|
"source-map-url": "^0.4.0",
|
||||||
"systemjs": "^6.3.2",
|
"systemjs": "^6.3.2",
|
||||||
"terser-webpack-plugin": "^5.1.4",
|
"terser-webpack-plugin": "^5.2.4",
|
||||||
"ts-lit-plugin": "^1.2.1",
|
"ts-lit-plugin": "^1.2.1",
|
||||||
"ts-mocha": "^8.0.0",
|
|
||||||
"typescript": "^4.3.5",
|
"typescript": "^4.3.5",
|
||||||
"vinyl-buffer": "^1.0.1",
|
"vinyl-buffer": "^1.0.1",
|
||||||
"vinyl-source-stream": "^2.0.0",
|
"vinyl-source-stream": "^2.0.0",
|
||||||
"webpack": "^5.43.0",
|
"webpack": "^5.55.1",
|
||||||
"webpack-cli": "^4.7.2",
|
"webpack-cli": "^4.8.0",
|
||||||
"webpack-dev-server": "^3.11.2",
|
"webpack-dev-server": "^4.3.0",
|
||||||
"webpack-manifest-plugin": "^3.1.1",
|
"webpack-manifest-plugin": "^4.0.2",
|
||||||
|
"webpackbar": "^5.0.0-3",
|
||||||
"workbox-build": "^6.1.5"
|
"workbox-build": "^6.1.5"
|
||||||
},
|
},
|
||||||
"_comment": "Polymer 3.2 contained a bug, fixed in https://github.com/Polymer/polymer/pull/5569, add as patch",
|
"_comment": "Polymer 3.2 contained a bug, fixed in https://github.com/Polymer/polymer/pull/5569, add as patch",
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
// Check for support of native locale string options
|
|
||||||
function checkToLocaleDateStringSupportsOptions() {
|
|
||||||
try {
|
|
||||||
new Date().toLocaleDateString("i");
|
|
||||||
} catch (e) {
|
|
||||||
return e.name === "RangeError";
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkToLocaleTimeStringSupportsOptions() {
|
|
||||||
try {
|
|
||||||
new Date().toLocaleTimeString("i");
|
|
||||||
} catch (e) {
|
|
||||||
return e.name === "RangeError";
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkToLocaleStringSupportsOptions() {
|
|
||||||
try {
|
|
||||||
new Date().toLocaleString("i");
|
|
||||||
} catch (e) {
|
|
||||||
return e.name === "RangeError";
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const toLocaleDateStringSupportsOptions =
|
|
||||||
checkToLocaleDateStringSupportsOptions();
|
|
||||||
export const toLocaleTimeStringSupportsOptions =
|
|
||||||
checkToLocaleTimeStringSupportsOptions();
|
|
||||||
export const toLocaleStringSupportsOptions =
|
|
||||||
checkToLocaleStringSupportsOptions();
|
|
|
@ -1,13 +1,15 @@
|
||||||
import { format } from "fecha";
|
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { FrontendLocaleData } from "../../data/translation";
|
import { FrontendLocaleData } from "../../data/translation";
|
||||||
import { toLocaleDateStringSupportsOptions } from "./check_options_support";
|
import { polyfillsLoaded } from "../translations/localize";
|
||||||
|
|
||||||
|
if (__BUILD__ === "latest" && polyfillsLoaded) {
|
||||||
|
await polyfillsLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
// Tuesday, August 10
|
// Tuesday, August 10
|
||||||
export const formatDateWeekday = toLocaleDateStringSupportsOptions
|
export const formatDateWeekday = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatDateWeekdayMem(locale).format(dateObj);
|
||||||
formatDateWeekdayMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date) => format(dateObj, "dddd, MMMM D");
|
|
||||||
const formatDateWeekdayMem = memoizeOne(
|
const formatDateWeekdayMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
|
@ -18,10 +20,9 @@ const formatDateWeekdayMem = memoizeOne(
|
||||||
);
|
);
|
||||||
|
|
||||||
// August 10, 2021
|
// August 10, 2021
|
||||||
export const formatDate = toLocaleDateStringSupportsOptions
|
export const formatDate = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatDateMem(locale).format(dateObj);
|
||||||
formatDateMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date) => format(dateObj, "MMMM D, YYYY");
|
|
||||||
const formatDateMem = memoizeOne(
|
const formatDateMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
|
@ -32,10 +33,9 @@ const formatDateMem = memoizeOne(
|
||||||
);
|
);
|
||||||
|
|
||||||
// 10/08/2021
|
// 10/08/2021
|
||||||
export const formatDateNumeric = toLocaleDateStringSupportsOptions
|
export const formatDateNumeric = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatDateNumericMem(locale).format(dateObj);
|
||||||
formatDateNumericMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date) => format(dateObj, "M/D/YYYY");
|
|
||||||
const formatDateNumericMem = memoizeOne(
|
const formatDateNumericMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
|
@ -46,10 +46,9 @@ const formatDateNumericMem = memoizeOne(
|
||||||
);
|
);
|
||||||
|
|
||||||
// Aug 10
|
// Aug 10
|
||||||
export const formatDateShort = toLocaleDateStringSupportsOptions
|
export const formatDateShort = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatDateShortMem(locale).format(dateObj);
|
||||||
formatDateShortMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date) => format(dateObj, "MMM D");
|
|
||||||
const formatDateShortMem = memoizeOne(
|
const formatDateShortMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
|
@ -59,10 +58,11 @@ const formatDateShortMem = memoizeOne(
|
||||||
);
|
);
|
||||||
|
|
||||||
// August 2021
|
// August 2021
|
||||||
export const formatDateMonthYear = toLocaleDateStringSupportsOptions
|
export const formatDateMonthYear = (
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
dateObj: Date,
|
||||||
formatDateMonthYearMem(locale).format(dateObj)
|
locale: FrontendLocaleData
|
||||||
: (dateObj: Date) => format(dateObj, "MMMM YYYY");
|
) => formatDateMonthYearMem(locale).format(dateObj);
|
||||||
|
|
||||||
const formatDateMonthYearMem = memoizeOne(
|
const formatDateMonthYearMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
|
@ -72,10 +72,9 @@ const formatDateMonthYearMem = memoizeOne(
|
||||||
);
|
);
|
||||||
|
|
||||||
// August
|
// August
|
||||||
export const formatDateMonth = toLocaleDateStringSupportsOptions
|
export const formatDateMonth = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatDateMonthMem(locale).format(dateObj);
|
||||||
formatDateMonthMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date) => format(dateObj, "MMMM");
|
|
||||||
const formatDateMonthMem = memoizeOne(
|
const formatDateMonthMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
|
@ -84,10 +83,9 @@ const formatDateMonthMem = memoizeOne(
|
||||||
);
|
);
|
||||||
|
|
||||||
// 2021
|
// 2021
|
||||||
export const formatDateYear = toLocaleDateStringSupportsOptions
|
export const formatDateYear = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatDateYearMem(locale).format(dateObj);
|
||||||
formatDateYearMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date) => format(dateObj, "YYYY");
|
|
||||||
const formatDateYearMem = memoizeOne(
|
const formatDateYearMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import { format } from "fecha";
|
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { FrontendLocaleData } from "../../data/translation";
|
import { FrontendLocaleData } from "../../data/translation";
|
||||||
import { toLocaleStringSupportsOptions } from "./check_options_support";
|
|
||||||
import { useAmPm } from "./use_am_pm";
|
import { useAmPm } from "./use_am_pm";
|
||||||
|
import { polyfillsLoaded } from "../translations/localize";
|
||||||
|
|
||||||
|
if (__BUILD__ === "latest" && polyfillsLoaded) {
|
||||||
|
await polyfillsLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
// August 9, 2021, 8:23 AM
|
// August 9, 2021, 8:23 AM
|
||||||
export const formatDateTime = toLocaleStringSupportsOptions
|
export const formatDateTime = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatDateTimeMem(locale).format(dateObj);
|
||||||
formatDateTimeMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date, locale: FrontendLocaleData) =>
|
|
||||||
format(dateObj, "MMMM D, YYYY, HH:mm" + useAmPm(locale) ? " A" : "");
|
|
||||||
const formatDateTimeMem = memoizeOne(
|
const formatDateTimeMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
|
@ -23,11 +24,11 @@ const formatDateTimeMem = memoizeOne(
|
||||||
);
|
);
|
||||||
|
|
||||||
// August 9, 2021, 8:23:15 AM
|
// August 9, 2021, 8:23:15 AM
|
||||||
export const formatDateTimeWithSeconds = toLocaleStringSupportsOptions
|
export const formatDateTimeWithSeconds = (
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
dateObj: Date,
|
||||||
formatDateTimeWithSecondsMem(locale).format(dateObj)
|
locale: FrontendLocaleData
|
||||||
: (dateObj: Date, locale: FrontendLocaleData) =>
|
) => formatDateTimeWithSecondsMem(locale).format(dateObj);
|
||||||
format(dateObj, "MMMM D, YYYY, HH:mm:ss" + useAmPm(locale) ? " A" : "");
|
|
||||||
const formatDateTimeWithSecondsMem = memoizeOne(
|
const formatDateTimeWithSecondsMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
|
@ -42,11 +43,11 @@ const formatDateTimeWithSecondsMem = memoizeOne(
|
||||||
);
|
);
|
||||||
|
|
||||||
// 9/8/2021, 8:23 AM
|
// 9/8/2021, 8:23 AM
|
||||||
export const formatDateTimeNumeric = toLocaleStringSupportsOptions
|
export const formatDateTimeNumeric = (
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
dateObj: Date,
|
||||||
formatDateTimeNumericMem(locale).format(dateObj)
|
locale: FrontendLocaleData
|
||||||
: (dateObj: Date, locale: FrontendLocaleData) =>
|
) => formatDateTimeNumericMem(locale).format(dateObj);
|
||||||
format(dateObj, "M/D/YYYY, HH:mm" + useAmPm(locale) ? " A" : "");
|
|
||||||
const formatDateTimeNumericMem = memoizeOne(
|
const formatDateTimeNumericMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
|
|
|
@ -1,30 +1,31 @@
|
||||||
import { format } from "fecha";
|
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { FrontendLocaleData } from "../../data/translation";
|
import { FrontendLocaleData } from "../../data/translation";
|
||||||
import { toLocaleTimeStringSupportsOptions } from "./check_options_support";
|
|
||||||
import { useAmPm } from "./use_am_pm";
|
import { useAmPm } from "./use_am_pm";
|
||||||
|
import { polyfillsLoaded } from "../translations/localize";
|
||||||
|
|
||||||
|
if (__BUILD__ === "latest" && polyfillsLoaded) {
|
||||||
|
await polyfillsLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
// 9:15 PM || 21:15
|
// 9:15 PM || 21:15
|
||||||
export const formatTime = toLocaleTimeStringSupportsOptions
|
export const formatTime = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatTimeMem(locale).format(dateObj);
|
||||||
formatTimeMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date, locale: FrontendLocaleData) =>
|
|
||||||
format(dateObj, "shortTime" + useAmPm(locale) ? " A" : "");
|
|
||||||
const formatTimeMem = memoizeOne(
|
const formatTimeMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
hour: useAmPm(locale) ? "numeric" : "2-digit",
|
hour: "numeric",
|
||||||
minute: "2-digit",
|
minute: "2-digit",
|
||||||
hour12: useAmPm(locale),
|
hour12: useAmPm(locale),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// 9:15:24 PM || 21:15:24
|
// 9:15:24 PM || 21:15:24
|
||||||
export const formatTimeWithSeconds = toLocaleTimeStringSupportsOptions
|
export const formatTimeWithSeconds = (
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
dateObj: Date,
|
||||||
formatTimeWithSecondsMem(locale).format(dateObj)
|
locale: FrontendLocaleData
|
||||||
: (dateObj: Date, locale: FrontendLocaleData) =>
|
) => formatTimeWithSecondsMem(locale).format(dateObj);
|
||||||
format(dateObj, "mediumTime" + useAmPm(locale) ? " A" : "");
|
|
||||||
const formatTimeWithSecondsMem = memoizeOne(
|
const formatTimeWithSecondsMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
|
@ -36,17 +37,15 @@ const formatTimeWithSecondsMem = memoizeOne(
|
||||||
);
|
);
|
||||||
|
|
||||||
// Tuesday 7:00 PM || Tuesday 19:00
|
// Tuesday 7:00 PM || Tuesday 19:00
|
||||||
export const formatTimeWeekday = toLocaleTimeStringSupportsOptions
|
export const formatTimeWeekday = (dateObj: Date, locale: FrontendLocaleData) =>
|
||||||
? (dateObj: Date, locale: FrontendLocaleData) =>
|
formatTimeWeekdayMem(locale).format(dateObj);
|
||||||
formatTimeWeekdayMem(locale).format(dateObj)
|
|
||||||
: (dateObj: Date, locale: FrontendLocaleData) =>
|
|
||||||
format(dateObj, "dddd, HH:mm" + useAmPm(locale) ? " A" : "");
|
|
||||||
const formatTimeWeekdayMem = memoizeOne(
|
const formatTimeWeekdayMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData) =>
|
(locale: FrontendLocaleData) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
weekday: "long",
|
|
||||||
hour: useAmPm(locale) ? "numeric" : "2-digit",
|
hour: useAmPm(locale) ? "numeric" : "2-digit",
|
||||||
minute: "2-digit",
|
minute: "2-digit",
|
||||||
|
second: "2-digit",
|
||||||
hour12: useAmPm(locale),
|
hour12: useAmPm(locale),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,48 +1,32 @@
|
||||||
import { LocalizeFunc } from "../translations/localize";
|
import { selectUnit } from "@formatjs/intl-utils";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { FrontendLocaleData } from "../../data/translation";
|
||||||
|
import { polyfillsLoaded } from "../translations/localize";
|
||||||
|
|
||||||
/**
|
if (__BUILD__ === "latest" && polyfillsLoaded) {
|
||||||
* Calculate a string representing a date object as relative time from now.
|
await polyfillsLoaded;
|
||||||
*
|
|
||||||
* Example output: 5 minutes ago, in 3 days.
|
|
||||||
*/
|
|
||||||
const tests = [60, 60, 24, 7];
|
|
||||||
const langKey = ["second", "minute", "hour", "day"];
|
|
||||||
|
|
||||||
export default function relativeTime(
|
|
||||||
dateObj: Date,
|
|
||||||
localize: LocalizeFunc,
|
|
||||||
options: {
|
|
||||||
compareTime?: Date;
|
|
||||||
includeTense?: boolean;
|
|
||||||
} = {}
|
|
||||||
): string {
|
|
||||||
const compareTime = options.compareTime || new Date();
|
|
||||||
let delta = (compareTime.getTime() - dateObj.getTime()) / 1000;
|
|
||||||
const tense = delta >= 0 ? "past" : "future";
|
|
||||||
delta = Math.abs(delta);
|
|
||||||
let roundedDelta = Math.round(delta);
|
|
||||||
|
|
||||||
if (roundedDelta === 0) {
|
|
||||||
return localize("ui.components.relative_time.just_now");
|
|
||||||
}
|
|
||||||
|
|
||||||
let unit = "week";
|
|
||||||
|
|
||||||
for (let i = 0; i < tests.length; i++) {
|
|
||||||
if (roundedDelta < tests[i]) {
|
|
||||||
unit = langKey[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
delta /= tests[i];
|
|
||||||
roundedDelta = Math.round(delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
return localize(
|
|
||||||
options.includeTense === false
|
|
||||||
? `ui.components.relative_time.duration.${unit}`
|
|
||||||
: `ui.components.relative_time.${tense}_duration.${unit}`,
|
|
||||||
"count",
|
|
||||||
roundedDelta
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const formatRelTimeMem = memoizeOne(
|
||||||
|
(locale: FrontendLocaleData) =>
|
||||||
|
// @ts-expect-error
|
||||||
|
new Intl.RelativeTimeFormat(locale.language, { numeric: "auto" })
|
||||||
|
);
|
||||||
|
|
||||||
|
export const relativeTime = (
|
||||||
|
from: Date,
|
||||||
|
locale: FrontendLocaleData,
|
||||||
|
to?: Date,
|
||||||
|
includeTense = true
|
||||||
|
): string => {
|
||||||
|
const diff = selectUnit(from, to);
|
||||||
|
if (includeTense) {
|
||||||
|
return formatRelTimeMem(locale).format(diff.value, diff.unit);
|
||||||
|
}
|
||||||
|
return Intl.NumberFormat(locale.language, {
|
||||||
|
style: "unit",
|
||||||
|
// @ts-expect-error
|
||||||
|
unit: diff.unit,
|
||||||
|
unitDisplay: "long",
|
||||||
|
}).format(Math.abs(diff.value));
|
||||||
|
};
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { FrontendLocaleData } from "../../data/translation";
|
||||||
import { formatDate } from "../datetime/format_date";
|
import { formatDate } from "../datetime/format_date";
|
||||||
import { formatDateTime } from "../datetime/format_date_time";
|
import { formatDateTime } from "../datetime/format_date_time";
|
||||||
import { formatTime } from "../datetime/format_time";
|
import { formatTime } from "../datetime/format_time";
|
||||||
import { formatNumber } from "../string/format_number";
|
import { formatNumber } from "../number/format_number";
|
||||||
import { LocalizeFunc } from "../translations/localize";
|
import { LocalizeFunc } from "../translations/localize";
|
||||||
import { computeStateDomain } from "./compute_state_domain";
|
import { computeStateDomain } from "./compute_state_domain";
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { FrontendLocaleData, NumberFormat } from "../../data/translation";
|
import { FrontendLocaleData, NumberFormat } from "../../data/translation";
|
||||||
import { round } from "../number/round";
|
import { round } from "./round";
|
||||||
|
|
||||||
export const numberFormatToLocale = (
|
export const numberFormatToLocale = (
|
||||||
localeOptions: FrontendLocaleData
|
localeOptions: FrontendLocaleData
|
|
@ -1,4 +1,7 @@
|
||||||
import { shouldPolyfill } from "@formatjs/intl-pluralrules/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/lib/should-polyfill";
|
||||||
import IntlMessageFormat from "intl-messageformat";
|
import IntlMessageFormat from "intl-messageformat";
|
||||||
import { Resources } from "../../types";
|
import { Resources } from "../../types";
|
||||||
|
|
||||||
|
@ -14,15 +17,35 @@ export interface FormatsType {
|
||||||
|
|
||||||
let loadedPolyfillLocale: Set<string> | undefined;
|
let loadedPolyfillLocale: Set<string> | undefined;
|
||||||
|
|
||||||
let polyfillLoaded = !shouldPolyfill();
|
const polyfillPluralRules = shouldPolyfillPluralRules();
|
||||||
const polyfillProm = polyfillLoaded
|
const polyfillRelativeTime = shouldPolyfillRelativeTime();
|
||||||
|
const polyfillDateTime = shouldPolyfillDateTime();
|
||||||
|
|
||||||
|
const polyfills: Promise<any>[] = [];
|
||||||
|
if (__BUILD__ === "latest") {
|
||||||
|
if (shouldPolyfillLocale()) {
|
||||||
|
polyfills.push(import("@formatjs/intl-locale/polyfill"));
|
||||||
|
}
|
||||||
|
if (polyfillPluralRules) {
|
||||||
|
polyfills.push(import("@formatjs/intl-pluralrules/polyfill"));
|
||||||
|
}
|
||||||
|
if (polyfillRelativeTime) {
|
||||||
|
polyfills.push(import("@formatjs/intl-relativetimeformat/polyfill"));
|
||||||
|
}
|
||||||
|
if (polyfillDateTime) {
|
||||||
|
polyfills.push(import("@formatjs/intl-datetimeformat/polyfill"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let polyfillLoaded = polyfills.length === 0;
|
||||||
|
export const polyfillsLoaded = polyfillLoaded
|
||||||
? undefined
|
? undefined
|
||||||
: import("@formatjs/intl-locale/polyfill")
|
: Promise.all(polyfills).then(() => {
|
||||||
.then(() => import("@formatjs/intl-pluralrules/polyfill"))
|
loadedPolyfillLocale = new Set();
|
||||||
.then(() => {
|
polyfillLoaded = true;
|
||||||
loadedPolyfillLocale = new Set();
|
// Load English so it becomes the default
|
||||||
polyfillLoaded = true;
|
return loadPolyfillLocales("en");
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapted from Polymer app-localize-behavior.
|
* Adapted from Polymer app-localize-behavior.
|
||||||
|
@ -52,17 +75,10 @@ export const computeLocalize = async (
|
||||||
formats?: FormatsType
|
formats?: FormatsType
|
||||||
): Promise<LocalizeFunc> => {
|
): Promise<LocalizeFunc> => {
|
||||||
if (!polyfillLoaded) {
|
if (!polyfillLoaded) {
|
||||||
await polyfillProm;
|
await polyfillsLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loadedPolyfillLocale && !loadedPolyfillLocale.has(language)) {
|
loadPolyfillLocales(language);
|
||||||
try {
|
|
||||||
loadedPolyfillLocale.add(language);
|
|
||||||
await import("@formatjs/intl-pluralrules/locale-data/en");
|
|
||||||
} catch (_e) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Everytime any of the parameters change, invalidate the strings cache.
|
// Everytime any of the parameters change, invalidate the strings cache.
|
||||||
cache._localizationCache = {};
|
cache._localizationCache = {};
|
||||||
|
@ -114,3 +130,23 @@ export const computeLocalize = async (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const loadPolyfillLocales = async (language: string) => {
|
||||||
|
if (!loadedPolyfillLocale || loadedPolyfillLocale.has(language)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loadedPolyfillLocale.add(language);
|
||||||
|
try {
|
||||||
|
if (polyfillPluralRules) {
|
||||||
|
await import(`@formatjs/intl-pluralrules/locale-data/${language}`);
|
||||||
|
}
|
||||||
|
if (polyfillRelativeTime) {
|
||||||
|
await import(`@formatjs/intl-relativetimeformat/locale-data/${language}`);
|
||||||
|
}
|
||||||
|
if (polyfillDateTime) {
|
||||||
|
await import(`@formatjs/intl-datetimeformat/locale-data/${language}`);
|
||||||
|
}
|
||||||
|
} catch (_e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { getColorByIndex } from "../../common/color/colors";
|
||||||
import {
|
import {
|
||||||
formatNumber,
|
formatNumber,
|
||||||
numberFormatToLocale,
|
numberFormatToLocale,
|
||||||
} from "../../common/string/format_number";
|
} from "../../common/number/format_number";
|
||||||
import { LineChartEntity, LineChartState } from "../../data/history";
|
import { LineChartEntity, LineChartState } from "../../data/history";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
import "./ha-chart-base";
|
import "./ha-chart-base";
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { customElement, property, state } from "lit/decorators";
|
||||||
import { getColorByIndex } from "../../common/color/colors";
|
import { getColorByIndex } from "../../common/color/colors";
|
||||||
import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time";
|
import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time";
|
||||||
import { computeDomain } from "../../common/entity/compute_domain";
|
import { computeDomain } from "../../common/entity/compute_domain";
|
||||||
import { numberFormatToLocale } from "../../common/string/format_number";
|
import { numberFormatToLocale } from "../../common/number/format_number";
|
||||||
import { computeRTL } from "../../common/util/compute_rtl";
|
import { computeRTL } from "../../common/util/compute_rtl";
|
||||||
import { TimelineEntity } from "../../data/history";
|
import { TimelineEntity } from "../../data/history";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { computeStateName } from "../../common/entity/compute_state_name";
|
||||||
import {
|
import {
|
||||||
formatNumber,
|
formatNumber,
|
||||||
numberFormatToLocale,
|
numberFormatToLocale,
|
||||||
} from "../../common/string/format_number";
|
} from "../../common/number/format_number";
|
||||||
import {
|
import {
|
||||||
getStatisticIds,
|
getStatisticIds,
|
||||||
Statistics,
|
Statistics,
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { computeStateDomain } from "../../common/entity/compute_state_domain";
|
||||||
import { computeStateName } from "../../common/entity/compute_state_name";
|
import { computeStateName } from "../../common/entity/compute_state_name";
|
||||||
import { stateIcon } from "../../common/entity/state_icon";
|
import { stateIcon } from "../../common/entity/state_icon";
|
||||||
import { timerTimeRemaining } from "../../data/timer";
|
import { timerTimeRemaining } from "../../data/timer";
|
||||||
import { formatNumber } from "../../common/string/format_number";
|
import { formatNumber } from "../../common/number/format_number";
|
||||||
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
|
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
import "../ha-label-badge";
|
import "../ha-label-badge";
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { formatNumber } from "../common/string/format_number";
|
import { formatNumber } from "../common/number/format_number";
|
||||||
import { CLIMATE_PRESET_NONE } from "../data/climate";
|
import { CLIMATE_PRESET_NONE } from "../data/climate";
|
||||||
import type { HomeAssistant } from "../types";
|
import type { HomeAssistant } from "../types";
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { css, LitElement, PropertyValues, svg, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { ifDefined } from "lit/directives/if-defined";
|
import { ifDefined } from "lit/directives/if-defined";
|
||||||
import { styleMap } from "lit/directives/style-map";
|
import { styleMap } from "lit/directives/style-map";
|
||||||
import { formatNumber } from "../common/string/format_number";
|
import { formatNumber } from "../common/number/format_number";
|
||||||
import { afterNextRender } from "../common/util/render-status";
|
import { afterNextRender } from "../common/util/render-status";
|
||||||
import { FrontendLocaleData } from "../data/translation";
|
import { FrontendLocaleData } from "../data/translation";
|
||||||
import { getValueInPercentage, normalize } from "../util/calculate";
|
import { getValueInPercentage, normalize } from "../util/calculate";
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { PropertyValues, ReactiveElement } from "lit";
|
import { PropertyValues, ReactiveElement } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import relativeTime from "../common/datetime/relative_time";
|
import { relativeTime } from "../common/datetime/relative_time";
|
||||||
import type { HomeAssistant } from "../types";
|
import type { HomeAssistant } from "../types";
|
||||||
|
|
||||||
@customElement("ha-relative-time")
|
@customElement("ha-relative-time")
|
||||||
|
@ -55,10 +55,7 @@ class HaRelativeTime extends ReactiveElement {
|
||||||
if (!this.datetime) {
|
if (!this.datetime) {
|
||||||
this.innerHTML = this.hass.localize("ui.components.relative_time.never");
|
this.innerHTML = this.hass.localize("ui.components.relative_time.never");
|
||||||
} else {
|
} else {
|
||||||
this.innerHTML = relativeTime(
|
this.innerHTML = relativeTime(new Date(this.datetime), this.hass.locale);
|
||||||
new Date(this.datetime),
|
|
||||||
this.hass.localize
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
/* eslint-plugin-disable lit */
|
/* eslint-plugin-disable lit */
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
import { computeStateDisplay } from "../common/entity/compute_state_display";
|
import { computeStateDisplay } from "../common/entity/compute_state_display";
|
||||||
import { formatNumber } from "../common/string/format_number";
|
import { formatNumber } from "../common/number/format_number";
|
||||||
import LocalizeMixin from "../mixins/localize-mixin";
|
import LocalizeMixin from "../mixins/localize-mixin";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { ifDefined } from "lit/directives/if-defined";
|
import { ifDefined } from "lit/directives/if-defined";
|
||||||
import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time";
|
import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time";
|
||||||
import relativeTime from "../../common/datetime/relative_time";
|
import { relativeTime } from "../../common/datetime/relative_time";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { toggleAttribute } from "../../common/dom/toggle_attribute";
|
import { toggleAttribute } from "../../common/dom/toggle_attribute";
|
||||||
import { LogbookEntry } from "../../data/logbook";
|
import { LogbookEntry } from "../../data/logbook";
|
||||||
|
@ -66,11 +66,7 @@ class RenderedTimeTracker {
|
||||||
renderTime(from: Date, to: Date): void {
|
renderTime(from: Date, to: Date): void {
|
||||||
this.entries.push(html`
|
this.entries.push(html`
|
||||||
<ha-timeline label>
|
<ha-timeline label>
|
||||||
${relativeTime(from, this.hass.localize, {
|
${relativeTime(from, this.hass.locale, to, false)} later
|
||||||
compareTime: to,
|
|
||||||
includeTense: false,
|
|
||||||
})}
|
|
||||||
later
|
|
||||||
</ha-timeline>
|
</ha-timeline>
|
||||||
`);
|
`);
|
||||||
this.lastReportedTime = to;
|
this.lastReportedTime = to;
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
} from "home-assistant-js-websocket";
|
} from "home-assistant-js-websocket";
|
||||||
import { css, html, svg, SVGTemplateResult, TemplateResult } from "lit";
|
import { css, html, svg, SVGTemplateResult, TemplateResult } from "lit";
|
||||||
import { styleMap } from "lit/directives/style-map";
|
import { styleMap } from "lit/directives/style-map";
|
||||||
import { formatNumber } from "../common/string/format_number";
|
import { formatNumber } from "../common/number/format_number";
|
||||||
import "../components/ha-icon";
|
import "../components/ha-icon";
|
||||||
import "../components/ha-svg-icon";
|
import "../components/ha-svg-icon";
|
||||||
import type { HomeAssistant } from "../types";
|
import type { HomeAssistant } from "../types";
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { formatTime } from "../../../common/datetime/format_time";
|
import { formatTime } from "../../../common/datetime/format_time";
|
||||||
import { formatNumber } from "../../../common/string/format_number";
|
import { formatNumber } from "../../../common/number/format_number";
|
||||||
import "../../../components/ha-relative-time";
|
import "../../../components/ha-relative-time";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ import {
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { formatDateWeekday } from "../../../common/datetime/format_date";
|
import { formatDateWeekday } from "../../../common/datetime/format_date";
|
||||||
import { formatTimeWeekday } from "../../../common/datetime/format_time";
|
import { formatTimeWeekday } from "../../../common/datetime/format_time";
|
||||||
import { formatNumber } from "../../../common/string/format_number";
|
import { formatNumber } from "../../../common/number/format_number";
|
||||||
import "../../../components/ha-svg-icon";
|
import "../../../components/ha-svg-icon";
|
||||||
import { getWeatherUnit, getWind } from "../../../data/weather";
|
import { getWeatherUnit, getWind } from "../../../data/weather";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { computeStateName } from "../../../../common/entity/compute_state_name";
|
||||||
import {
|
import {
|
||||||
formatNumber,
|
formatNumber,
|
||||||
numberFormatToLocale,
|
numberFormatToLocale,
|
||||||
} from "../../../../common/string/format_number";
|
} from "../../../../common/number/format_number";
|
||||||
import "../../../../components/chart/ha-chart-base";
|
import "../../../../components/chart/ha-chart-base";
|
||||||
import type HaChartBase from "../../../../components/chart/ha-chart-base";
|
import type HaChartBase from "../../../../components/chart/ha-chart-base";
|
||||||
import "../../../../components/ha-card";
|
import "../../../../components/ha-card";
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { css, html, LitElement, svg } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { formatNumber } from "../../../../common/string/format_number";
|
import { formatNumber } from "../../../../common/number/format_number";
|
||||||
import "../../../../components/ha-card";
|
import "../../../../components/ha-card";
|
||||||
import "../../../../components/ha-svg-icon";
|
import "../../../../components/ha-svg-icon";
|
||||||
import {
|
import {
|
||||||
|
|
|
@ -32,7 +32,7 @@ import "../../../../components/chart/ha-chart-base";
|
||||||
import {
|
import {
|
||||||
formatNumber,
|
formatNumber,
|
||||||
numberFormatToLocale,
|
numberFormatToLocale,
|
||||||
} from "../../../../common/string/format_number";
|
} from "../../../../common/number/format_number";
|
||||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||||
import { FrontendLocaleData } from "../../../../data/translation";
|
import { FrontendLocaleData } from "../../../../data/translation";
|
||||||
import {
|
import {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import "@polymer/paper-tooltip";
|
||||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { formatNumber } from "../../../../common/string/format_number";
|
import { formatNumber } from "../../../../common/number/format_number";
|
||||||
import "../../../../components/ha-card";
|
import "../../../../components/ha-card";
|
||||||
import "../../../../components/ha-svg-icon";
|
import "../../../../components/ha-svg-icon";
|
||||||
import "../../../../components/ha-gauge";
|
import "../../../../components/ha-gauge";
|
||||||
|
|
|
@ -33,7 +33,7 @@ import "../../../../components/chart/ha-chart-base";
|
||||||
import {
|
import {
|
||||||
formatNumber,
|
formatNumber,
|
||||||
numberFormatToLocale,
|
numberFormatToLocale,
|
||||||
} from "../../../../common/string/format_number";
|
} from "../../../../common/number/format_number";
|
||||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||||
import { FrontendLocaleData } from "../../../../data/translation";
|
import { FrontendLocaleData } from "../../../../data/translation";
|
||||||
import {
|
import {
|
||||||
|
|
|
@ -19,7 +19,7 @@ import {
|
||||||
} from "../../../../common/color/convert-color";
|
} from "../../../../common/color/convert-color";
|
||||||
import { labDarken } from "../../../../common/color/lab";
|
import { labDarken } from "../../../../common/color/lab";
|
||||||
import { computeStateName } from "../../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../../common/entity/compute_state_name";
|
||||||
import { formatNumber } from "../../../../common/string/format_number";
|
import { formatNumber } from "../../../../common/number/format_number";
|
||||||
import "../../../../components/chart/statistics-chart";
|
import "../../../../components/chart/statistics-chart";
|
||||||
import "../../../../components/ha-card";
|
import "../../../../components/ha-card";
|
||||||
import {
|
import {
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { computeStateName } from "../../../../common/entity/compute_state_name";
|
||||||
import {
|
import {
|
||||||
formatNumber,
|
formatNumber,
|
||||||
numberFormatToLocale,
|
numberFormatToLocale,
|
||||||
} from "../../../../common/string/format_number";
|
} from "../../../../common/number/format_number";
|
||||||
import "../../../../components/chart/ha-chart-base";
|
import "../../../../components/chart/ha-chart-base";
|
||||||
import "../../../../components/ha-card";
|
import "../../../../components/ha-card";
|
||||||
import { EnergyData, getEnergyDataCollection } from "../../../../data/energy";
|
import { EnergyData, getEnergyDataCollection } from "../../../../data/energy";
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { computeStateDomain } from "../../../common/entity/compute_state_domain"
|
||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
import { stateIcon } from "../../../common/entity/state_icon";
|
import { stateIcon } from "../../../common/entity/state_icon";
|
||||||
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
|
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
|
||||||
import { formatNumber } from "../../../common/string/format_number";
|
import { formatNumber } from "../../../common/number/format_number";
|
||||||
import { iconColorCSS } from "../../../common/style/icon_color_css";
|
import { iconColorCSS } from "../../../common/style/icon_color_css";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import "../../../components/ha-icon";
|
import "../../../components/ha-icon";
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import { ifDefined } from "lit/directives/if-defined";
|
import { ifDefined } from "lit/directives/if-defined";
|
||||||
import relativeTime from "../../../common/datetime/relative_time";
|
import { relativeTime } from "../../../common/datetime/relative_time";
|
||||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||||
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||||
|
@ -330,7 +330,7 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard {
|
||||||
: entityConf.show_last_changed
|
: entityConf.show_last_changed
|
||||||
? relativeTime(
|
? relativeTime(
|
||||||
new Date(stateObj.last_changed),
|
new Date(stateObj.last_changed),
|
||||||
this.hass!.localize
|
this.hass!.locale
|
||||||
)
|
)
|
||||||
: computeStateDisplay(
|
: computeStateDisplay(
|
||||||
this.hass!.localize,
|
this.hass!.localize,
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { UNIT_F } from "../../../common/const";
|
||||||
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
import { formatNumber } from "../../../common/string/format_number";
|
import { formatNumber } from "../../../common/number/format_number";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import type { HaCard } from "../../../components/ha-card";
|
import type { HaCard } from "../../../components/ha-card";
|
||||||
import "../../../components/ha-icon-button";
|
import "../../../components/ha-icon-button";
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { computeStateDisplay } from "../../../common/entity/compute_state_displa
|
||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
import { stateIcon } from "../../../common/entity/state_icon";
|
import { stateIcon } from "../../../common/entity/state_icon";
|
||||||
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
|
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
|
||||||
import { formatNumber } from "../../../common/string/format_number";
|
import { formatNumber } from "../../../common/number/format_number";
|
||||||
import { debounce } from "../../../common/util/debounce";
|
import { debounce } from "../../../common/util/debounce";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import "../../../components/ha-icon";
|
import "../../../components/ha-icon";
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { customElement, property, state } from "lit/decorators";
|
||||||
import { formatDate } from "../../../common/datetime/format_date";
|
import { formatDate } from "../../../common/datetime/format_date";
|
||||||
import { formatDateTime } from "../../../common/datetime/format_date_time";
|
import { formatDateTime } from "../../../common/datetime/format_date_time";
|
||||||
import { formatTime } from "../../../common/datetime/format_time";
|
import { formatTime } from "../../../common/datetime/format_time";
|
||||||
import relativeTime from "../../../common/datetime/relative_time";
|
import { relativeTime } from "../../../common/datetime/relative_time";
|
||||||
import { FrontendLocaleData } from "../../../data/translation";
|
import { FrontendLocaleData } from "../../../data/translation";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { TimestampRenderingFormat } from "./types";
|
import { TimestampRenderingFormat } from "./types";
|
||||||
|
@ -103,11 +103,13 @@ class HuiTimestampDisplay extends LitElement {
|
||||||
if (this.ts && this.hass!.localize) {
|
if (this.ts && this.hass!.localize) {
|
||||||
this._relative =
|
this._relative =
|
||||||
this._format === "relative"
|
this._format === "relative"
|
||||||
? relativeTime(this.ts, this.hass!.localize)
|
? relativeTime(this.ts, this.hass!.locale)
|
||||||
: (this._relative = relativeTime(new Date(), this.hass!.localize, {
|
: (this._relative = relativeTime(
|
||||||
compareTime: this.ts,
|
new Date(),
|
||||||
includeTense: false,
|
this.hass!.locale,
|
||||||
}));
|
this.ts,
|
||||||
|
false
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { computeDomain } from "../../../common/entity/compute_domain";
|
||||||
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
import { stateIcon } from "../../../common/entity/state_icon";
|
import { stateIcon } from "../../../common/entity/state_icon";
|
||||||
import { formatNumber } from "../../../common/string/format_number";
|
import { formatNumber } from "../../../common/number/format_number";
|
||||||
import "../../../components/entity/state-badge";
|
import "../../../components/entity/state-badge";
|
||||||
import { UNAVAILABLE_STATES } from "../../../data/entity";
|
import { UNAVAILABLE_STATES } from "../../../data/entity";
|
||||||
import { ActionHandlerEvent } from "../../../data/lovelace";
|
import { ActionHandlerEvent } from "../../../data/lovelace";
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {
|
||||||
} from "lit";
|
} from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import checkValidDate from "../../../common/datetime/check_valid_date";
|
import checkValidDate from "../../../common/datetime/check_valid_date";
|
||||||
import { formatNumber } from "../../../common/string/format_number";
|
import { formatNumber } from "../../../common/number/format_number";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import { formatAttributeValue } from "../../../util/hass-attributes-util";
|
import { formatAttributeValue } from "../../../util/hass-attributes-util";
|
||||||
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { mdiDelete } from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import relativeTime from "../../common/datetime/relative_time";
|
import { relativeTime } from "../../common/datetime/relative_time";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import "../../components/ha-card";
|
import "../../components/ha-card";
|
||||||
import "../../components/ha-settings-row";
|
import "../../components/ha-settings-row";
|
||||||
|
@ -69,10 +69,7 @@ class HaLongLivedTokens extends LitElement {
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.profile.long_lived_access_tokens.created",
|
"ui.panel.profile.long_lived_access_tokens.created",
|
||||||
"date",
|
"date",
|
||||||
relativeTime(
|
relativeTime(new Date(token.created_at), this.hass.locale)
|
||||||
new Date(token.created_at),
|
|
||||||
this.hass.localize
|
|
||||||
)
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<mwc-icon-button
|
<mwc-icon-button
|
||||||
|
|
|
@ -3,7 +3,7 @@ import "@polymer/paper-listbox/paper-listbox";
|
||||||
import { html, LitElement, TemplateResult } from "lit";
|
import { html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { formatNumber } from "../../common/string/format_number";
|
import { formatNumber } from "../../common/number/format_number";
|
||||||
import "../../components/ha-card";
|
import "../../components/ha-card";
|
||||||
import "../../components/ha-paper-dropdown-menu";
|
import "../../components/ha-paper-dropdown-menu";
|
||||||
import "../../components/ha-settings-row";
|
import "../../components/ha-settings-row";
|
||||||
|
|
|
@ -4,7 +4,7 @@ import "@polymer/paper-tooltip/paper-tooltip";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import relativeTime from "../../common/datetime/relative_time";
|
import { relativeTime } from "../../common/datetime/relative_time";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import "../../components/ha-card";
|
import "../../components/ha-card";
|
||||||
import "../../components/ha-settings-row";
|
import "../../components/ha-settings-row";
|
||||||
|
@ -64,7 +64,7 @@ class HaRefreshTokens extends LitElement {
|
||||||
{
|
{
|
||||||
date: relativeTime(
|
date: relativeTime(
|
||||||
new Date(token.created_at),
|
new Date(token.created_at),
|
||||||
this.hass.localize
|
this.hass.locale
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
|
@ -76,7 +76,7 @@ class HaRefreshTokens extends LitElement {
|
||||||
{
|
{
|
||||||
date: relativeTime(
|
date: relativeTime(
|
||||||
new Date(token.last_used_at),
|
new Date(token.last_used_at),
|
||||||
this.hass.localize
|
this.hass.locale
|
||||||
),
|
),
|
||||||
location: token.last_used_ip,
|
location: token.last_used_ip,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,19 @@
|
||||||
import "core-js";
|
import "core-js";
|
||||||
import "regenerator-runtime/runtime";
|
import "regenerator-runtime/runtime";
|
||||||
import "lit/polyfill-support";
|
import "lit/polyfill-support";
|
||||||
// For localize
|
|
||||||
|
// For localize & formatting
|
||||||
import "@formatjs/intl-getcanonicallocales/polyfill";
|
import "@formatjs/intl-getcanonicallocales/polyfill";
|
||||||
|
import "@formatjs/intl-locale/polyfill";
|
||||||
|
import "@formatjs/intl-pluralrules/polyfill";
|
||||||
|
import "@formatjs/intl-pluralrules/locale-data/en";
|
||||||
|
import "@formatjs/intl-numberformat/polyfill";
|
||||||
|
import "@formatjs/intl-numberformat/locale-data/en";
|
||||||
|
import "@formatjs/intl-relativetimeformat/polyfill";
|
||||||
|
import "@formatjs/intl-relativetimeformat/locale-data/en";
|
||||||
|
import "@formatjs/intl-datetimeformat/polyfill";
|
||||||
|
import "@formatjs/intl-datetimeformat/locale-data/en";
|
||||||
|
|
||||||
// To use comlink under ES5
|
// To use comlink under ES5
|
||||||
import "proxy-polyfill";
|
import "proxy-polyfill";
|
||||||
import "unfetch/polyfill";
|
import "unfetch/polyfill";
|
||||||
|
|
|
@ -436,29 +436,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relative_time": {
|
"relative_time": {
|
||||||
"never": "Never",
|
"never": "Never"
|
||||||
"just_now": "Just now",
|
|
||||||
"duration": {
|
|
||||||
"second": "{count} {count, plural,\n one {second}\n other {seconds}\n}",
|
|
||||||
"minute": "{count} {count, plural,\n one {minute}\n other {minutes}\n}",
|
|
||||||
"hour": "{count} {count, plural,\n one {hour}\n other {hours}\n}",
|
|
||||||
"day": "{count} {count, plural,\n one {day}\n other {days}\n}",
|
|
||||||
"week": "{count} {count, plural,\n one {week}\n other {weeks}\n}"
|
|
||||||
},
|
|
||||||
"past_duration": {
|
|
||||||
"second": "{count} {count, plural,\n one {second}\n other {seconds}\n} ago",
|
|
||||||
"minute": "{count} {count, plural,\n one {minute}\n other {minutes}\n} ago",
|
|
||||||
"hour": "{count} {count, plural,\n one {hour}\n other {hours}\n} ago",
|
|
||||||
"day": "{count} {count, plural,\n one {day}\n other {days}\n} ago",
|
|
||||||
"week": "{count} {count, plural,\n one {week}\n other {weeks}\n} ago"
|
|
||||||
},
|
|
||||||
"future_duration": {
|
|
||||||
"second": "In {count} {count, plural,\n one {second}\n other {seconds}\n}",
|
|
||||||
"minute": "In {count} {count, plural,\n one {minute}\n other {minutes}\n}",
|
|
||||||
"hour": "In {count} {count, plural,\n one {hour}\n other {hours}\n}",
|
|
||||||
"day": "In {count} {count, plural,\n one {day}\n other {days}\n}",
|
|
||||||
"week": "In {count} {count, plural,\n one {week}\n other {weeks}\n}"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"history_charts": {
|
"history_charts": {
|
||||||
"history_disabled": "History integration disabled",
|
"history_disabled": "History integration disabled",
|
||||||
|
|
|
@ -1,217 +0,0 @@
|
||||||
import { assert } from "chai";
|
|
||||||
|
|
||||||
import relativeTime from "../../../src/common/datetime/relative_time";
|
|
||||||
|
|
||||||
describe("relativeTime", () => {
|
|
||||||
// Mock localize function for testing
|
|
||||||
const localize = (message, ...args) =>
|
|
||||||
message + (args.length ? ": " + args.join(",") : "");
|
|
||||||
|
|
||||||
it("now", () => {
|
|
||||||
const now = new Date();
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(now, localize, { compareTime: now }),
|
|
||||||
"ui.components.relative_time.just_now"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("past_second", () => {
|
|
||||||
const inputdt = new Date("2021-02-03T11:22:00+00:00");
|
|
||||||
const compare = new Date("2021-02-03T11:22:33+00:00");
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, { compareTime: compare }),
|
|
||||||
"ui.components.relative_time.past_duration.second: count,33"
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, {
|
|
||||||
compareTime: compare,
|
|
||||||
includeTense: false,
|
|
||||||
}),
|
|
||||||
"ui.components.relative_time.duration.second: count,33"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("past_minute", () => {
|
|
||||||
const inputdt = new Date("2021-02-03T11:20:33+00:00");
|
|
||||||
const compare = new Date("2021-02-03T11:22:33+00:00");
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, { compareTime: compare }),
|
|
||||||
"ui.components.relative_time.past_duration.minute: count,2"
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, {
|
|
||||||
compareTime: compare,
|
|
||||||
includeTense: false,
|
|
||||||
}),
|
|
||||||
"ui.components.relative_time.duration.minute: count,2"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("past_hour", () => {
|
|
||||||
const inputdt = new Date("2021-02-03T09:22:33+00:00");
|
|
||||||
const compare = new Date("2021-02-03T11:22:33+00:00");
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, { compareTime: compare }),
|
|
||||||
"ui.components.relative_time.past_duration.hour: count,2"
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, {
|
|
||||||
compareTime: compare,
|
|
||||||
includeTense: false,
|
|
||||||
}),
|
|
||||||
"ui.components.relative_time.duration.hour: count,2"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("past_day", () => {
|
|
||||||
let inputdt = new Date("2021-02-01T11:22:33+00:00");
|
|
||||||
let compare = new Date("2021-02-03T11:22:33+00:00");
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, { compareTime: compare }),
|
|
||||||
"ui.components.relative_time.past_duration.day: count,2"
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, {
|
|
||||||
compareTime: compare,
|
|
||||||
includeTense: false,
|
|
||||||
}),
|
|
||||||
"ui.components.relative_time.duration.day: count,2"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Test switch from days to weeks
|
|
||||||
inputdt = new Date("2021-01-28T11:22:33+00:00");
|
|
||||||
compare = new Date("2021-02-03T11:22:33+00:00");
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, {
|
|
||||||
compareTime: compare,
|
|
||||||
includeTense: false,
|
|
||||||
}),
|
|
||||||
"ui.components.relative_time.duration.day: count,6"
|
|
||||||
);
|
|
||||||
inputdt = new Date("2021-01-27T11:22:33+00:00");
|
|
||||||
compare = new Date("2021-02-03T11:22:33+00:00");
|
|
||||||
assert.notStrictEqual(
|
|
||||||
relativeTime(inputdt, localize, {
|
|
||||||
compareTime: compare,
|
|
||||||
includeTense: false,
|
|
||||||
}),
|
|
||||||
"ui.components.relative_time.duration.day: count,7"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("past_week", () => {
|
|
||||||
const inputdt = new Date("2021-01-03T11:22:33+00:00");
|
|
||||||
const compare = new Date("2021-02-03T11:22:33+00:00");
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, { compareTime: compare }),
|
|
||||||
"ui.components.relative_time.past_duration.week: count,4"
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, {
|
|
||||||
compareTime: compare,
|
|
||||||
includeTense: false,
|
|
||||||
}),
|
|
||||||
"ui.components.relative_time.duration.week: count,4"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("future_second", () => {
|
|
||||||
const inputdt = new Date("2021-02-03T11:22:55+00:00");
|
|
||||||
const compare = new Date("2021-02-03T11:22:33+00:00");
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, { compareTime: compare }),
|
|
||||||
"ui.components.relative_time.future_duration.second: count,22"
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, {
|
|
||||||
compareTime: compare,
|
|
||||||
includeTense: false,
|
|
||||||
}),
|
|
||||||
"ui.components.relative_time.duration.second: count,22"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("future_minute", () => {
|
|
||||||
const inputdt = new Date("2021-02-03T11:24:33+00:00");
|
|
||||||
const compare = new Date("2021-02-03T11:22:33+00:00");
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, { compareTime: compare }),
|
|
||||||
"ui.components.relative_time.future_duration.minute: count,2"
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, {
|
|
||||||
compareTime: compare,
|
|
||||||
includeTense: false,
|
|
||||||
}),
|
|
||||||
"ui.components.relative_time.duration.minute: count,2"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("future_hour", () => {
|
|
||||||
const inputdt = new Date("2021-02-03T13:22:33+00:00");
|
|
||||||
const compare = new Date("2021-02-03T11:22:33+00:00");
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, { compareTime: compare }),
|
|
||||||
"ui.components.relative_time.future_duration.hour: count,2"
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, {
|
|
||||||
compareTime: compare,
|
|
||||||
includeTense: false,
|
|
||||||
}),
|
|
||||||
"ui.components.relative_time.duration.hour: count,2"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("future_day", () => {
|
|
||||||
let inputdt = new Date("2021-02-05T11:22:33+00:00");
|
|
||||||
let compare = new Date("2021-02-03T11:22:33+00:00");
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, { compareTime: compare }),
|
|
||||||
"ui.components.relative_time.future_duration.day: count,2"
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, {
|
|
||||||
compareTime: compare,
|
|
||||||
includeTense: false,
|
|
||||||
}),
|
|
||||||
"ui.components.relative_time.duration.day: count,2"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Test switch from days to weeks
|
|
||||||
inputdt = new Date("2021-02-09T11:22:33+00:00");
|
|
||||||
compare = new Date("2021-02-03T11:22:33+00:00");
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, {
|
|
||||||
compareTime: compare,
|
|
||||||
includeTense: false,
|
|
||||||
}),
|
|
||||||
"ui.components.relative_time.duration.day: count,6"
|
|
||||||
);
|
|
||||||
inputdt = new Date("2021-02-10T11:22:33+00:00");
|
|
||||||
compare = new Date("2021-02-03T11:22:33+00:00");
|
|
||||||
assert.notStrictEqual(
|
|
||||||
relativeTime(inputdt, localize, {
|
|
||||||
compareTime: compare,
|
|
||||||
includeTense: false,
|
|
||||||
}),
|
|
||||||
"ui.components.relative_time.duration.day: count,7"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("future_week", () => {
|
|
||||||
const inputdt = new Date("2021-03-03T11:22:33+00:00");
|
|
||||||
const compare = new Date("2021-02-03T11:22:33+00:00");
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, { compareTime: compare }),
|
|
||||||
"ui.components.relative_time.future_duration.week: count,4"
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
relativeTime(inputdt, localize, {
|
|
||||||
compareTime: compare,
|
|
||||||
includeTense: false,
|
|
||||||
}),
|
|
||||||
"ui.components.relative_time.duration.week: count,4"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -16,7 +16,7 @@ describe("formatDateTime", () => {
|
||||||
number_format: NumberFormat.language,
|
number_format: NumberFormat.language,
|
||||||
time_format: TimeFormat.am_pm,
|
time_format: TimeFormat.am_pm,
|
||||||
}),
|
}),
|
||||||
"November 18, 2017, 11:12 PM"
|
"November 18, 2017 at 11:12 PM"
|
||||||
);
|
);
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
formatDateTime(dateObj, {
|
formatDateTime(dateObj, {
|
||||||
|
@ -24,7 +24,7 @@ describe("formatDateTime", () => {
|
||||||
number_format: NumberFormat.language,
|
number_format: NumberFormat.language,
|
||||||
time_format: TimeFormat.twenty_four,
|
time_format: TimeFormat.twenty_four,
|
||||||
}),
|
}),
|
||||||
"November 18, 2017, 23:12"
|
"November 18, 2017 at 23:12"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -39,7 +39,7 @@ describe("formatDateTimeWithSeconds", () => {
|
||||||
number_format: NumberFormat.language,
|
number_format: NumberFormat.language,
|
||||||
time_format: TimeFormat.am_pm,
|
time_format: TimeFormat.am_pm,
|
||||||
}),
|
}),
|
||||||
"November 18, 2017, 11:12:13 PM"
|
"November 18, 2017 at 11:12:13 PM"
|
||||||
);
|
);
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
formatDateTimeWithSeconds(dateObj, {
|
formatDateTimeWithSeconds(dateObj, {
|
||||||
|
@ -47,7 +47,7 @@ describe("formatDateTimeWithSeconds", () => {
|
||||||
number_format: NumberFormat.language,
|
number_format: NumberFormat.language,
|
||||||
time_format: TimeFormat.twenty_four,
|
time_format: TimeFormat.twenty_four,
|
||||||
}),
|
}),
|
||||||
"November 18, 2017, 23:12:13"
|
"November 18, 2017 at 23:12:13"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -0,0 +1,115 @@
|
||||||
|
import { assert } from "chai";
|
||||||
|
|
||||||
|
import { relativeTime } from "../../../src/common/datetime/relative_time";
|
||||||
|
import { NumberFormat, TimeFormat } from "../../../src/data/translation";
|
||||||
|
|
||||||
|
describe("relativeTime", () => {
|
||||||
|
const locale = {
|
||||||
|
language: "en",
|
||||||
|
number_format: NumberFormat.language,
|
||||||
|
time_format: TimeFormat.language,
|
||||||
|
};
|
||||||
|
|
||||||
|
it("now", () => {
|
||||||
|
const now = new Date();
|
||||||
|
assert.strictEqual(relativeTime(now, locale, now), "now");
|
||||||
|
assert.strictEqual(relativeTime(now, locale, now, false), "0 seconds");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("past_second", () => {
|
||||||
|
const inputdt = new Date("2021-02-03T11:22:00+00:00");
|
||||||
|
const compare = new Date("2021-02-03T11:22:33+00:00");
|
||||||
|
assert.strictEqual(
|
||||||
|
relativeTime(inputdt, locale, compare),
|
||||||
|
"33 seconds ago"
|
||||||
|
);
|
||||||
|
assert.strictEqual(
|
||||||
|
relativeTime(inputdt, locale, compare, false),
|
||||||
|
"33 seconds"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("past_minute", () => {
|
||||||
|
const inputdt = new Date("2021-02-03T11:20:33+00:00");
|
||||||
|
const compare = new Date("2021-02-03T11:22:33+00:00");
|
||||||
|
assert.strictEqual(relativeTime(inputdt, locale, compare), "2 minutes ago");
|
||||||
|
assert.strictEqual(
|
||||||
|
relativeTime(inputdt, locale, compare, false),
|
||||||
|
"2 minutes"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("past_hour", () => {
|
||||||
|
const inputdt = new Date("2021-02-03T09:22:33+00:00");
|
||||||
|
const compare = new Date("2021-02-03T11:22:33+00:00");
|
||||||
|
assert.strictEqual(relativeTime(inputdt, locale, compare), "2 hours ago");
|
||||||
|
assert.strictEqual(
|
||||||
|
relativeTime(inputdt, locale, compare, false),
|
||||||
|
"2 hours"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("past_day", () => {
|
||||||
|
const inputdt = new Date("2021-02-01T11:22:33+00:00");
|
||||||
|
const compare = new Date("2021-02-03T11:22:33+00:00");
|
||||||
|
assert.strictEqual(relativeTime(inputdt, locale, compare), "2 days ago");
|
||||||
|
assert.strictEqual(relativeTime(inputdt, locale, compare, false), "2 days");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("future_second", () => {
|
||||||
|
const inputdt = new Date("2021-02-03T11:22:55+00:00");
|
||||||
|
const compare = new Date("2021-02-03T11:22:33+00:00");
|
||||||
|
assert.strictEqual(relativeTime(inputdt, locale, compare), "in 22 seconds");
|
||||||
|
assert.strictEqual(
|
||||||
|
relativeTime(inputdt, locale, compare, false),
|
||||||
|
"22 seconds"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("future_minute", () => {
|
||||||
|
const inputdt = new Date("2021-02-03T11:24:33+00:00");
|
||||||
|
const compare = new Date("2021-02-03T11:22:33+00:00");
|
||||||
|
assert.strictEqual(relativeTime(inputdt, locale, compare), "in 2 minutes");
|
||||||
|
assert.strictEqual(
|
||||||
|
relativeTime(inputdt, locale, compare, false),
|
||||||
|
"2 minutes"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("future_hour", () => {
|
||||||
|
const inputdt = new Date("2021-02-03T13:22:33+00:00");
|
||||||
|
const compare = new Date("2021-02-03T11:22:33+00:00");
|
||||||
|
assert.strictEqual(relativeTime(inputdt, locale, compare), "in 2 hours");
|
||||||
|
assert.strictEqual(
|
||||||
|
relativeTime(inputdt, locale, compare, false),
|
||||||
|
"2 hours"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("future_day", () => {
|
||||||
|
const inputdt = new Date("2021-02-05T11:22:33+00:00");
|
||||||
|
const compare = new Date("2021-02-03T11:22:33+00:00");
|
||||||
|
assert.strictEqual(relativeTime(inputdt, locale, compare), "in 2 days");
|
||||||
|
assert.strictEqual(relativeTime(inputdt, locale, compare, false), "2 days");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("future_week", () => {
|
||||||
|
const inputdt = new Date("2021-03-24T11:22:33+00:00");
|
||||||
|
const compare = new Date("2021-03-03T11:22:33+00:00");
|
||||||
|
assert.strictEqual(relativeTime(inputdt, locale, compare), "in 3 weeks");
|
||||||
|
assert.strictEqual(
|
||||||
|
relativeTime(inputdt, locale, compare, false),
|
||||||
|
"3 weeks"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("future_month", () => {
|
||||||
|
const inputdt = new Date("2021-03-03T11:22:33+00:00");
|
||||||
|
const compare = new Date("2021-02-03T11:22:33+00:00");
|
||||||
|
assert.strictEqual(relativeTime(inputdt, locale, compare), "next month");
|
||||||
|
assert.strictEqual(
|
||||||
|
relativeTime(inputdt, locale, compare, false),
|
||||||
|
"1 month"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
|
@ -172,14 +172,14 @@ describe("computeStateDisplay", () => {
|
||||||
it("Uses am/pm time format", () => {
|
it("Uses am/pm time format", () => {
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
computeStateDisplay(localize, stateObj, localeData),
|
computeStateDisplay(localize, stateObj, localeData),
|
||||||
"November 18, 2017, 11:12 PM"
|
"November 18, 2017 at 11:12 PM"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("Uses 24h time format", () => {
|
it("Uses 24h time format", () => {
|
||||||
localeData.time_format = TimeFormat.twenty_four;
|
localeData.time_format = TimeFormat.twenty_four;
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
computeStateDisplay(localize, stateObj, localeData),
|
computeStateDisplay(localize, stateObj, localeData),
|
||||||
"November 18, 2017, 23:12"
|
"November 18, 2017 at 23:12"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -259,7 +259,7 @@ describe("computeStateDisplay", () => {
|
||||||
localeData,
|
localeData,
|
||||||
"2021-07-04 15:40:03"
|
"2021-07-04 15:40:03"
|
||||||
),
|
),
|
||||||
"July 4, 2021, 3:40 PM"
|
"July 4, 2021 at 3:40 PM"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("Uses 24h time format", () => {
|
it("Uses 24h time format", () => {
|
||||||
|
@ -271,7 +271,7 @@ describe("computeStateDisplay", () => {
|
||||||
localeData,
|
localeData,
|
||||||
"2021-07-04 15:40:03"
|
"2021-07-04 15:40:03"
|
||||||
),
|
),
|
||||||
"July 4, 2021, 15:40"
|
"July 4, 2021 at 15:40"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -1,6 +1,6 @@
|
||||||
import { assert } from "chai";
|
import { assert } from "chai";
|
||||||
|
|
||||||
import { formatNumber } from "../../../src/common/string/format_number";
|
import { formatNumber } from "../../../src/common/number/format_number";
|
||||||
import {
|
import {
|
||||||
FrontendLocaleData,
|
FrontendLocaleData,
|
||||||
NumberFormat,
|
NumberFormat,
|
|
@ -0,0 +1,12 @@
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
process.env.TZ = "Etc/UTC";
|
||||||
|
process.env.IS_TEST = "true";
|
||||||
|
|
||||||
|
const MDI_OUTPUT_DIR = path.resolve(__dirname, "../build/mdi");
|
||||||
|
|
||||||
|
if (!fs.existsSync(MDI_OUTPUT_DIR)) {
|
||||||
|
fs.mkdirSync(MDI_OUTPUT_DIR, { recursive: true });
|
||||||
|
fs.writeFileSync(path.resolve(MDI_OUTPUT_DIR, "iconMetadata.json"), "{}");
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
const { createAppConfig } = require("../build-scripts/webpack.js");
|
||||||
|
|
||||||
|
module.exports = createAppConfig({
|
||||||
|
isProdBuild: false,
|
||||||
|
latestBuild: true,
|
||||||
|
isStatsBuild: false,
|
||||||
|
});
|
Loading…
Reference in New Issue