mirror of
https://github.com/vector-im/element-call.git
synced 2024-11-27 00:48:06 +08:00
Load the Intl.Segmenter and Intl.DurationFormat polyfills only if needed (#2778)
* Load the Intl.Segmenter polyfill only if needed * Also polyfill Intl.DurationFormat only if needed * Polyfill Intl.* in tests * Load the default translations in tests * Instanciate the Intl.DurationFormat in the component
This commit is contained in:
parent
6e5c468780
commit
137a53dbee
6
src/@types/global.d.ts
vendored
6
src/@types/global.d.ts
vendored
@ -6,6 +6,7 @@ Please see LICENSE in the repository root for full details.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import "matrix-js-sdk/src/@types/global";
|
import "matrix-js-sdk/src/@types/global";
|
||||||
|
import type { DurationFormat as PolyfillDurationFormat } from "@formatjs/intl-durationformat";
|
||||||
import { Controls } from "../controls";
|
import { Controls } from "../controls";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@ -23,4 +24,9 @@ declare global {
|
|||||||
// Safari only supports this prefixed, so tell the type system about it
|
// Safari only supports this prefixed, so tell the type system about it
|
||||||
webkitRequestFullscreen: () => void;
|
webkitRequestFullscreen: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Intl {
|
||||||
|
// Add DurationFormat as part of the Intl namespace because we polyfill it
|
||||||
|
const DurationFormat: typeof PolyfillDurationFormat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,9 @@ import { expect, test } from "vitest";
|
|||||||
|
|
||||||
import { Initializer } from "../src/initializer";
|
import { Initializer } from "../src/initializer";
|
||||||
|
|
||||||
test("initBeforeReact sets font family from URL param", () => {
|
test("initBeforeReact sets font family from URL param", async () => {
|
||||||
window.location.hash = "#?font=DejaVu Sans";
|
window.location.hash = "#?font=DejaVu Sans";
|
||||||
Initializer.initBeforeReact();
|
await Initializer.initBeforeReact();
|
||||||
expect(
|
expect(
|
||||||
getComputedStyle(document.documentElement).getPropertyValue(
|
getComputedStyle(document.documentElement).getPropertyValue(
|
||||||
"--font-family",
|
"--font-family",
|
||||||
@ -19,9 +19,9 @@ test("initBeforeReact sets font family from URL param", () => {
|
|||||||
).toBe('"DejaVu Sans"');
|
).toBe('"DejaVu Sans"');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("initBeforeReact sets font scale from URL param", () => {
|
test("initBeforeReact sets font scale from URL param", async () => {
|
||||||
window.location.hash = "#?fontScale=1.2";
|
window.location.hash = "#?fontScale=1.2";
|
||||||
Initializer.initBeforeReact();
|
await Initializer.initBeforeReact();
|
||||||
expect(
|
expect(
|
||||||
getComputedStyle(document.documentElement).getPropertyValue("--font-scale"),
|
getComputedStyle(document.documentElement).getPropertyValue("--font-scale"),
|
||||||
).toBe("1.2");
|
).toBe("1.2");
|
||||||
|
@ -11,6 +11,8 @@ import LanguageDetector from "i18next-browser-languagedetector";
|
|||||||
import Backend from "i18next-http-backend";
|
import Backend from "i18next-http-backend";
|
||||||
import * as Sentry from "@sentry/react";
|
import * as Sentry from "@sentry/react";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
import { shouldPolyfill as shouldPolyfillSegmenter } from "@formatjs/intl-segmenter/should-polyfill";
|
||||||
|
import { shouldPolyfill as shouldPolyfillDurationFormat } from "@formatjs/intl-durationformat/should-polyfill";
|
||||||
|
|
||||||
import { getUrlParams } from "./UrlParams";
|
import { getUrlParams } from "./UrlParams";
|
||||||
import { Config } from "./config/Config";
|
import { Config } from "./config/Config";
|
||||||
@ -41,10 +43,17 @@ export class Initializer {
|
|||||||
return Initializer.internalInstance?.isInitialized;
|
return Initializer.internalInstance?.isInitialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static initBeforeReact(): void {
|
public static async initBeforeReact(): Promise<void> {
|
||||||
// this maybe also needs to return a promise in the future,
|
const polyfills: Promise<unknown>[] = [];
|
||||||
// if we have to do async inits before showing the loading screen
|
if (shouldPolyfillSegmenter()) {
|
||||||
// but this should be avoided if possible
|
polyfills.push(import("@formatjs/intl-segmenter/polyfill-force"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldPolyfillDurationFormat()) {
|
||||||
|
polyfills.push(import("@formatjs/intl-durationformat/polyfill-force"));
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(polyfills);
|
||||||
|
|
||||||
//i18n
|
//i18n
|
||||||
const languageDetector = new LanguageDetector();
|
const languageDetector = new LanguageDetector();
|
||||||
@ -54,7 +63,7 @@ export class Initializer {
|
|||||||
lookup: () => getUrlParams().lang ?? undefined,
|
lookup: () => getUrlParams().lang ?? undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
i18n
|
await i18n
|
||||||
.use(Backend)
|
.use(Backend)
|
||||||
.use(languageDetector)
|
.use(languageDetector)
|
||||||
.use(initReactI18next)
|
.use(initReactI18next)
|
||||||
@ -74,9 +83,6 @@ export class Initializer {
|
|||||||
order: ["urlFragment", "navigator"],
|
order: ["urlFragment", "navigator"],
|
||||||
caches: [],
|
caches: [],
|
||||||
},
|
},
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
logger.error("Failed to initialize i18n", e);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Custom Themeing
|
// Custom Themeing
|
||||||
|
23
src/main.tsx
23
src/main.tsx
@ -20,8 +20,6 @@ import {
|
|||||||
setLogExtension as setLKLogExtension,
|
setLogExtension as setLKLogExtension,
|
||||||
setLogLevel as setLKLogLevel,
|
setLogLevel as setLKLogLevel,
|
||||||
} from "livekit-client";
|
} from "livekit-client";
|
||||||
import "@formatjs/intl-segmenter/polyfill";
|
|
||||||
import "@formatjs/intl-durationformat/polyfill";
|
|
||||||
|
|
||||||
import { App } from "./App";
|
import { App } from "./App";
|
||||||
import { init as initRageshake } from "./settings/rageshake";
|
import { init as initRageshake } from "./settings/rageshake";
|
||||||
@ -57,12 +55,17 @@ if (fatalError !== null) {
|
|||||||
throw fatalError; // Stop the app early
|
throw fatalError; // Stop the app early
|
||||||
}
|
}
|
||||||
|
|
||||||
Initializer.initBeforeReact();
|
Initializer.initBeforeReact()
|
||||||
|
.then(() => {
|
||||||
|
const history = createBrowserHistory();
|
||||||
|
|
||||||
const history = createBrowserHistory();
|
root.render(
|
||||||
|
<StrictMode>
|
||||||
root.render(
|
<App history={history} />
|
||||||
<StrictMode>
|
</StrictMode>,
|
||||||
<App history={history} />
|
);
|
||||||
</StrictMode>,
|
})
|
||||||
);
|
.catch((e) => {
|
||||||
|
logger.error("Failed to initialize app", e);
|
||||||
|
root.render(e.message);
|
||||||
|
});
|
||||||
|
@ -11,19 +11,12 @@ import {
|
|||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useState,
|
useState,
|
||||||
|
useMemo,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { DurationFormat } from "@formatjs/intl-durationformat";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { ReactionIndicator } from "./ReactionIndicator";
|
import { ReactionIndicator } from "./ReactionIndicator";
|
||||||
|
|
||||||
const durationFormatter = new DurationFormat(undefined, {
|
|
||||||
minutesDisplay: "always",
|
|
||||||
secondsDisplay: "always",
|
|
||||||
hoursDisplay: "auto",
|
|
||||||
style: "digital",
|
|
||||||
});
|
|
||||||
|
|
||||||
export function RaisedHandIndicator({
|
export function RaisedHandIndicator({
|
||||||
raisedHandTime,
|
raisedHandTime,
|
||||||
miniature,
|
miniature,
|
||||||
@ -38,6 +31,17 @@ export function RaisedHandIndicator({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [raisedHandDuration, setRaisedHandDuration] = useState("");
|
const [raisedHandDuration, setRaisedHandDuration] = useState("");
|
||||||
|
|
||||||
|
const durationFormatter = useMemo(
|
||||||
|
() =>
|
||||||
|
new Intl.DurationFormat(undefined, {
|
||||||
|
minutesDisplay: "always",
|
||||||
|
secondsDisplay: "always",
|
||||||
|
hoursDisplay: "auto",
|
||||||
|
style: "digital",
|
||||||
|
}),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
const clickCallback = useCallback<MouseEventHandler<HTMLButtonElement>>(
|
const clickCallback = useCallback<MouseEventHandler<HTMLButtonElement>>(
|
||||||
(event) => {
|
(event) => {
|
||||||
if (!onClick) {
|
if (!onClick) {
|
||||||
@ -69,7 +73,7 @@ export function RaisedHandIndicator({
|
|||||||
calculateTime();
|
calculateTime();
|
||||||
const to = setInterval(calculateTime, 1000);
|
const to = setInterval(calculateTime, 1000);
|
||||||
return (): void => clearInterval(to);
|
return (): void => clearInterval(to);
|
||||||
}, [setRaisedHandDuration, raisedHandTime, showTimer]);
|
}, [setRaisedHandDuration, raisedHandTime, showTimer, durationFormatter]);
|
||||||
|
|
||||||
if (!raisedHandTime) {
|
if (!raisedHandTime) {
|
||||||
return;
|
return;
|
||||||
|
@ -6,6 +6,8 @@ Please see LICENSE in the repository root for full details.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import "global-jsdom/register";
|
import "global-jsdom/register";
|
||||||
|
import "@formatjs/intl-durationformat/polyfill";
|
||||||
|
import "@formatjs/intl-segmenter/polyfill";
|
||||||
import i18n from "i18next";
|
import i18n from "i18next";
|
||||||
import posthog from "posthog-js";
|
import posthog from "posthog-js";
|
||||||
import { initReactI18next } from "react-i18next";
|
import { initReactI18next } from "react-i18next";
|
||||||
@ -14,6 +16,7 @@ import { cleanup } from "@testing-library/react";
|
|||||||
import "vitest-axe/extend-expect";
|
import "vitest-axe/extend-expect";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
|
||||||
|
import EN_GB from "../public/locales/en-GB/app.json";
|
||||||
import { Config } from "./config/Config";
|
import { Config } from "./config/Config";
|
||||||
|
|
||||||
// Bare-minimum i18n config
|
// Bare-minimum i18n config
|
||||||
@ -22,6 +25,13 @@ i18n
|
|||||||
.init({
|
.init({
|
||||||
lng: "en-GB",
|
lng: "en-GB",
|
||||||
fallbackLng: "en-GB",
|
fallbackLng: "en-GB",
|
||||||
|
supportedLngs: ["en-GB"],
|
||||||
|
// We embed the translations, so that it never needs to fetch
|
||||||
|
resources: {
|
||||||
|
"en-GB": {
|
||||||
|
app: EN_GB,
|
||||||
|
},
|
||||||
|
},
|
||||||
interpolation: {
|
interpolation: {
|
||||||
escapeValue: false, // React has built-in XSS protections
|
escapeValue: false, // React has built-in XSS protections
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user