From a1b64dad13b5d11d1cd617f87e453eef409b84d0 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 29 Sep 2023 14:30:25 +0100 Subject: [PATCH 01/10] Update matrix-web-i18n Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- package.json | 2 +- src/@types/common.ts | 35 +---------------------------------- yarn.lock | 9 +++++---- 3 files changed, 7 insertions(+), 39 deletions(-) diff --git a/package.json b/package.json index 54d27efe979..f8b64b0193f 100644 --- a/package.json +++ b/package.json @@ -214,7 +214,7 @@ "jsqr": "^1.4.0", "mailhog": "^4.16.0", "matrix-mock-request": "^2.5.0", - "matrix-web-i18n": "^2.1.0", + "matrix-web-i18n": "^3.1.1", "mocha-junit-reporter": "^2.2.0", "node-fetch": "2", "postcss-scss": "^4.0.4", diff --git a/src/@types/common.ts b/src/@types/common.ts index dd42c2078f2..ba2401f6a8c 100644 --- a/src/@types/common.ts +++ b/src/@types/common.ts @@ -23,40 +23,7 @@ export type Writeable = { -readonly [P in keyof T]: T[P] }; export type ComponentClass = keyof JSX.IntrinsicElements | JSXElementConstructor; -/** - * Utility type for string dot notation for accessing nested object properties. - * Based on https://stackoverflow.com/a/58436959 - * @example - * { - * "a": { - * "b": { - * "c": "value" - * }, - * "d": "foobar" - * } - * } - * will yield a type of `"a.b.c" | "a.d"` with Separator="." - * @typeParam Target the target type to generate leaf keys for - * @typeParam Separator the separator to use between key segments when accessing nested objects - * @typeParam LeafType the type which leaves of this object extend, used to determine when to stop recursion - * @typeParam MaxDepth the maximum depth to recurse to - * @returns a union type representing all dot (Separator) string notation keys which can access a Leaf (of LeafType) - */ -export type Leaves = [ - MaxDepth, -] extends [never] - ? never - : Target extends LeafType - ? "" - : { - [K in keyof Target]-?: Join, Separator>; - }[keyof Target]; -type Prev = [never, 0, 1, 2, 3, ...0[]]; -type Join = K extends string | number - ? P extends string | number - ? `${K}${"" extends P ? "" : S}${P}` - : never - : never; +export type { Leaves } from "matrix-web-i18n"; export type RecursivePartial = { [P in keyof T]?: T[P] extends (infer U)[] diff --git a/yarn.lock b/yarn.lock index c70d88de9fa..dd3ea3db0f6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7677,14 +7677,15 @@ matrix-mock-request@^2.5.0: dependencies: expect "^28.1.0" -matrix-web-i18n@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/matrix-web-i18n/-/matrix-web-i18n-2.1.0.tgz#bab2db9ac462773de829053b4b8d43c11154a85b" - integrity sha512-z+B9D/PkWYB4O9SP4lsG4KNA2V3ypMWstP+lreft1c1wz6L5R1U3ennp+cs3yOsylBfcK+xLRvkwLNZsU6QEUA== +matrix-web-i18n@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/matrix-web-i18n/-/matrix-web-i18n-3.1.1.tgz#da851748515b20ca15fa986817bbce2e242b3dd6" + integrity sha512-BOeOTedtONIqVQUlyHFXpxXkrETWdCoJdToyA+edMU+yGjKOW7bekAd9uAEfkV9jErP5eXw3cHYsKZPpa8ifWg== dependencies: "@babel/parser" "^7.18.5" "@babel/traverse" "^7.18.5" lodash "^4.17.21" + minimist "^1.2.8" walk "^2.3.15" matrix-widget-api@^1.5.0, matrix-widget-api@^1.6.0: From 6d98abd62324197f1a5510fbb394152019f0ca73 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 29 Sep 2023 14:32:00 +0100 Subject: [PATCH 02/10] Fix custom translations for structured JSON nested fields Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/languageHandler.tsx | 73 ++++++++--------------------------- test/languageHandler-test.tsx | 53 +++++++++++++++++++++---- 2 files changed, 62 insertions(+), 64 deletions(-) diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx index 28fa218c998..c963cf9b27d 100644 --- a/src/languageHandler.tsx +++ b/src/languageHandler.tsx @@ -21,7 +21,10 @@ import counterpart from "counterpart"; import React from "react"; import { logger } from "matrix-js-sdk/src/logger"; import { Optional } from "matrix-events-sdk"; -import { MapWithDefault, safeSet } from "matrix-js-sdk/src/utils"; +import { MapWithDefault } from "matrix-js-sdk/src/utils"; +import { normalizeLanguageKey, TranslationKey as _TranslationKey, KEY_SEPARATOR } from "matrix-web-i18n"; +import { TranslationStringsObject } from "@matrix-org/react-sdk-module-api"; +import _ from "lodash"; import type Translations from "./i18n/strings/en_EN.json"; import SettingsStore from "./settings/SettingsStore"; @@ -30,11 +33,12 @@ import { SettingLevel } from "./settings/SettingLevel"; import { retry } from "./utils/promise"; import SdkConfig from "./SdkConfig"; import { ModuleRunner } from "./modules/ModuleRunner"; -import { Leaves } from "./@types/common"; // @ts-ignore - $webapp is a webpack resolve alias pointing to the output directory, see webpack config import webpackLangJsonUrl from "$webapp/i18n/languages.json"; +export { Translation, normalizeLanguageKey, getNormalizedLanguageKeys } from "matrix-web-i18n"; + const i18nFolder = "i18n/"; // Control whether to also return original, untranslated strings @@ -42,7 +46,7 @@ const i18nFolder = "i18n/"; const ANNOTATE_STRINGS = false; // We use english strings as keys, some of which contain full stops -counterpart.setSeparator("|"); +counterpart.setSeparator(KEY_SEPARATOR); // see `translateWithFallback` for an explanation of fallback handling const FALLBACK_LOCALE = "en"; @@ -110,7 +114,7 @@ export function getUserLanguage(): string { * } * } */ -export type TranslationKey = Leaves; +export type TranslationKey = _TranslationKey; // Function which only purpose is to mark that a string is translatable // Does not actually do anything. It's helpful for automatic extraction of translatable strings @@ -541,41 +545,6 @@ export function getLanguageFromBrowser(): string { return getLanguagesFromBrowser()[0]; } -/** - * Turns a language string, normalises it, - * (see normalizeLanguageKey) into an array of language strings - * with fallback to generic languages - * (eg. 'pt-BR' => ['pt-br', 'pt']) - * - * @param {string} language The input language string - * @return {string[]} List of normalised languages - */ -export function getNormalizedLanguageKeys(language: string): string[] { - const languageKeys: string[] = []; - const normalizedLanguage = normalizeLanguageKey(language); - const languageParts = normalizedLanguage.split("-"); - if (languageParts.length === 2 && languageParts[0] === languageParts[1]) { - languageKeys.push(languageParts[0]); - } else { - languageKeys.push(normalizedLanguage); - if (languageParts.length === 2) { - languageKeys.push(languageParts[0]); - } - } - return languageKeys; -} - -/** - * Returns a language string with underscores replaced with - * hyphens, and lowercased. - * - * @param {string} language The language string to be normalized - * @returns {string} The normalized language string - */ -export function normalizeLanguageKey(language: string): string { - return language.toLowerCase().replace("_", "-"); -} - export function getCurrentLanguage(): string { return counterpart.getLocale(); } @@ -662,34 +631,26 @@ async function getLanguage(langPath: string): Promise { return res.json(); } -export interface ICustomTranslations { - // Format is a map of english string to language to override - [str: string]: { - [lang: string]: string; - }; -} - -let cachedCustomTranslations: Optional = null; +let cachedCustomTranslations: Optional = null; let cachedCustomTranslationsExpire = 0; // zero to trigger expiration right away // This awkward class exists so the test runner can get at the function. It is // not intended for practical or realistic usage. export class CustomTranslationOptions { - public static lookupFn?: (url: string) => ICustomTranslations; + public static lookupFn?: (url: string) => TranslationStringsObject; private constructor() { // static access for tests only } } -function doRegisterTranslations(customTranslations: ICustomTranslations): void { - // We convert the operator-friendly version into something counterpart can - // consume. +function doRegisterTranslations(customTranslations: TranslationStringsObject): void { + // We convert the operator-friendly version into something counterpart can consume. // Map: lang → Record: string → translation const langs: MapWithDefault> = new MapWithDefault(() => ({})); - for (const [str, translations] of Object.entries(customTranslations)) { - for (const [lang, newStr] of Object.entries(translations)) { - safeSet(langs.getOrCreate(lang), str, newStr); + for (const [translationKey, translations] of Object.entries(customTranslations)) { + for (const [lang, translation] of Object.entries(translations)) { + _.set(langs.getOrCreate(lang), translationKey.split(KEY_SEPARATOR), translation); } } @@ -719,11 +680,11 @@ export async function registerCustomTranslations({ if (!lookupUrl) return; // easy - nothing to do try { - let json: Optional; + let json: Optional; if (testOnlyIgnoreCustomTranslationsCache || Date.now() >= cachedCustomTranslationsExpire) { json = CustomTranslationOptions.lookupFn ? CustomTranslationOptions.lookupFn(lookupUrl) - : ((await (await fetch(lookupUrl)).json()) as ICustomTranslations); + : ((await (await fetch(lookupUrl)).json()) as TranslationStringsObject); cachedCustomTranslations = json; // Set expiration to the future, but not too far. Just trying to avoid diff --git a/test/languageHandler-test.tsx b/test/languageHandler-test.tsx index f8c273900fc..20e9ff949de 100644 --- a/test/languageHandler-test.tsx +++ b/test/languageHandler-test.tsx @@ -16,6 +16,7 @@ limitations under the License. import React from "react"; import fetchMock from "fetch-mock-jest"; +import { TranslationStringsObject } from "@matrix-org/react-sdk-module-api"; import SdkConfig from "../src/SdkConfig"; import { @@ -23,7 +24,6 @@ import { _tDom, CustomTranslationOptions, getAllLanguagesWithLabels, - ICustomTranslations, registerCustomTranslations, setLanguage, setMissingEntryGenerator, @@ -34,10 +34,11 @@ import { } from "../src/languageHandler"; import { stubClient } from "./test-utils"; import { setupLanguageMock } from "./setup/setupLanguage"; +import { Translation } from "../../matrix-web-i18n"; -async function setupTranslationOverridesForTests(overrides: ICustomTranslations) { +async function setupTranslationOverridesForTests(overrides: TranslationStringsObject) { const lookupUrl = "/translations.json"; - const fn = (url: string): ICustomTranslations => { + const fn = (url: string): TranslationStringsObject => { expect(url).toEqual(lookupUrl); return overrides; }; @@ -62,15 +63,15 @@ describe("languageHandler", () => { }); it("should support overriding translations", async () => { - const str = "This is a test string that does not exist in the app." as TranslationKey; - const enOverride = "This is the English version of a custom string." as TranslationKey; - const deOverride = "This is the German version of a custom string." as TranslationKey; + const str: TranslationKey = "power_level|default"; + const enOverride: Translation = "Visitor"; + const deOverride: Translation = "Besucher"; // First test that overrides aren't being used await setLanguage("en"); - expect(_t(str)).toEqual(str); + expect(_t(str)).toMatchInlineSnapshot(`"Default"`); await setLanguage("de"); - expect(_t(str)).toEqual(str); + expect(_t(str)).toMatchInlineSnapshot(`"Standard"`); await setupTranslationOverridesForTests({ [str]: { @@ -87,6 +88,42 @@ describe("languageHandler", () => { expect(_t(str)).toEqual(deOverride); }); + it("should support overriding plural translations", async () => { + const str: TranslationKey = "voip|n_people_joined"; + const enOverride: Translation = { + other: "%(count)s people in the call", + one: "%(count)s person in the call", + }; + const deOverride: Translation = { + other: "%(count)s Personen im Anruf", + one: "%(count)s Person im Anruf", + }; + + // First test that overrides aren't being used + await setLanguage("en"); + expect(_t(str, { count: 1 })).toMatchInlineSnapshot(`"1 person joined"`); + expect(_t(str, { count: 5 })).toMatchInlineSnapshot(`"5 people joined"`); + await setLanguage("de"); + expect(_t(str, { count: 1 })).toMatchInlineSnapshot(`"1 Person beigetreten"`); + expect(_t(str, { count: 5 })).toMatchInlineSnapshot(`"5 Personen beigetreten"`); + + await setupTranslationOverridesForTests({ + [str]: { + en: enOverride, + de: deOverride, + }, + }); + + // Now test that they *are* being used + await setLanguage("en"); + expect(_t(str, { count: 1 })).toMatchInlineSnapshot(`"1 person in the call"`); + expect(_t(str, { count: 5 })).toMatchInlineSnapshot(`"5 people in the call"`); + + await setLanguage("de"); + expect(_t(str, { count: 1 })).toMatchInlineSnapshot(`"1 Person im Anruf"`); + expect(_t(str, { count: 5 })).toMatchInlineSnapshot(`"5 Personen im Anruf"`); + }); + describe("UserFriendlyError", () => { const testErrorMessage = "This email address is already in use (%(email)s)" as TranslationKey; beforeEach(async () => { From 691fcd293835ce1bdda89d2023796c51b221669f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 29 Sep 2023 14:38:19 +0100 Subject: [PATCH 03/10] Fix import Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- test/languageHandler-test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/languageHandler-test.tsx b/test/languageHandler-test.tsx index 20e9ff949de..046b06b4ec4 100644 --- a/test/languageHandler-test.tsx +++ b/test/languageHandler-test.tsx @@ -31,10 +31,10 @@ import { TranslatedString, UserFriendlyError, TranslationKey, + Translation, } from "../src/languageHandler"; import { stubClient } from "./test-utils"; import { setupLanguageMock } from "./setup/setupLanguage"; -import { Translation } from "../../matrix-web-i18n"; async function setupTranslationOverridesForTests(overrides: TranslationStringsObject) { const lookupUrl = "/translations.json"; From 2e59b0d31b4f8d15edcfa08d17b38ad3cf4d408e Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 29 Sep 2023 14:38:39 +0100 Subject: [PATCH 04/10] Fix export Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/languageHandler.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx index c963cf9b27d..3ae448cb440 100644 --- a/src/languageHandler.tsx +++ b/src/languageHandler.tsx @@ -37,7 +37,8 @@ import { ModuleRunner } from "./modules/ModuleRunner"; // @ts-ignore - $webapp is a webpack resolve alias pointing to the output directory, see webpack config import webpackLangJsonUrl from "$webapp/i18n/languages.json"; -export { Translation, normalizeLanguageKey, getNormalizedLanguageKeys } from "matrix-web-i18n"; +export type { Translation } from "matrix-web-i18n"; +export { normalizeLanguageKey, getNormalizedLanguageKeys } from "matrix-web-i18n"; const i18nFolder = "i18n/"; From 22b9246cd02829515644e3920ab9ea19585a854c Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 29 Sep 2023 17:33:39 +0100 Subject: [PATCH 05/10] Update @matrix-org/react-sdk-module-api Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f8b64b0193f..a4e0d03ac8e 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@matrix-org/analytics-events": "^0.7.0", "@matrix-org/emojibase-bindings": "^1.1.2", "@matrix-org/matrix-wysiwyg": "^2.4.1", - "@matrix-org/react-sdk-module-api": "^2.1.0", + "@matrix-org/react-sdk-module-api": "^2.1.1", "@matrix-org/spec": "^1.7.0", "@sentry/browser": "^7.0.0", "@sentry/tracing": "^7.0.0", diff --git a/yarn.lock b/yarn.lock index dd3ea3db0f6..02ef5d83901 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1916,10 +1916,10 @@ version "3.2.14" resolved "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz#acd96c00a881d0f462e1f97a56c73742c8dbc984" -"@matrix-org/react-sdk-module-api@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@matrix-org/react-sdk-module-api/-/react-sdk-module-api-2.1.0.tgz#ca9d67853512fda1df2786810b90be31dd8dc7b1" - integrity sha512-SARD5BsmZYv1hvuezLfBUafJ9+rPLbk5WO0S3vZgkLH3jJQrk7f/65qBB5fLKF2ljprfZ1GTpuBeq04wn7Tnmg== +"@matrix-org/react-sdk-module-api@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@matrix-org/react-sdk-module-api/-/react-sdk-module-api-2.1.1.tgz#54e8617c15185010d608c0325ecaec8d1574d12b" + integrity sha512-dYPY3aXtNwPrg2aEmFeWddMdohus/Ha17XES2QH+WMCawt+hH+uq28jH1EmW1RUOOzxVcdY36lRGOwqRtAJbhA== dependencies: "@babel/runtime" "^7.17.9" From 73bec4403c6750b6db0534cd29faf92a5611a27b Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 2 Oct 2023 10:10:46 +0100 Subject: [PATCH 06/10] Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/languageHandler.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx index 3ae448cb440..0a80be89f48 100644 --- a/src/languageHandler.tsx +++ b/src/languageHandler.tsx @@ -37,7 +37,6 @@ import { ModuleRunner } from "./modules/ModuleRunner"; // @ts-ignore - $webapp is a webpack resolve alias pointing to the output directory, see webpack config import webpackLangJsonUrl from "$webapp/i18n/languages.json"; -export type { Translation } from "matrix-web-i18n"; export { normalizeLanguageKey, getNormalizedLanguageKeys } from "matrix-web-i18n"; const i18nFolder = "i18n/"; From 2dec52640c910dfa0701ac24e38829d1156e2bd5 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 2 Oct 2023 10:15:19 +0100 Subject: [PATCH 07/10] Delint Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dd08072a9d9..6b3c9e20c41 100644 --- a/package.json +++ b/package.json @@ -233,4 +233,4 @@ "outputName": "jest-sonar-report.xml", "relativePaths": true } -} \ No newline at end of file +} From 1be088e33f531f20c09d44db53632a80d5a4a95f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 2 Oct 2023 10:16:06 +0100 Subject: [PATCH 08/10] Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- test/languageHandler-test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/languageHandler-test.tsx b/test/languageHandler-test.tsx index 046b06b4ec4..c77988f3b1c 100644 --- a/test/languageHandler-test.tsx +++ b/test/languageHandler-test.tsx @@ -16,6 +16,7 @@ limitations under the License. import React from "react"; import fetchMock from "fetch-mock-jest"; +import { Translation } from "matrix-web-i18n"; import { TranslationStringsObject } from "@matrix-org/react-sdk-module-api"; import SdkConfig from "../src/SdkConfig"; @@ -31,7 +32,6 @@ import { TranslatedString, UserFriendlyError, TranslationKey, - Translation, } from "../src/languageHandler"; import { stubClient } from "./test-utils"; import { setupLanguageMock } from "./setup/setupLanguage"; From eb21dead4ddea5c51b9dfebd2c9fd4d8a0ad7de2 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 2 Oct 2023 10:41:43 +0100 Subject: [PATCH 09/10] Update matrix-web-i18n Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6b3c9e20c41..158f314d9ad 100644 --- a/package.json +++ b/package.json @@ -214,7 +214,7 @@ "jsqr": "^1.4.0", "mailhog": "^4.16.0", "matrix-mock-request": "^2.5.0", - "matrix-web-i18n": "^3.1.1", + "matrix-web-i18n": "^3.1.2", "mocha-junit-reporter": "^2.2.0", "node-fetch": "2", "postcss-scss": "^4.0.4", diff --git a/yarn.lock b/yarn.lock index 74b5170fb3d..0dc0958be63 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7677,10 +7677,10 @@ matrix-mock-request@^2.5.0: dependencies: expect "^28.1.0" -matrix-web-i18n@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/matrix-web-i18n/-/matrix-web-i18n-3.1.1.tgz#da851748515b20ca15fa986817bbce2e242b3dd6" - integrity sha512-BOeOTedtONIqVQUlyHFXpxXkrETWdCoJdToyA+edMU+yGjKOW7bekAd9uAEfkV9jErP5eXw3cHYsKZPpa8ifWg== +matrix-web-i18n@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/matrix-web-i18n/-/matrix-web-i18n-3.1.2.tgz#c5a51516dc5379688875f377ee03e34f91b91624" + integrity sha512-HBqpjkR9jMPEVq4WuAwDNTkgME85EDstVCyaeaEDmFYpo1FclMDSeXnZgj3FM3RKNXDRLVHdSo+FA1626JuF6Q== dependencies: "@babel/parser" "^7.18.5" "@babel/traverse" "^7.18.5" From 192f5b449592ba9d5d62df16a452deada0305a0f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 2 Oct 2023 11:04:13 +0100 Subject: [PATCH 10/10] Update matrix-web-i18n Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 158f314d9ad..7a4e41e67d2 100644 --- a/package.json +++ b/package.json @@ -214,7 +214,7 @@ "jsqr": "^1.4.0", "mailhog": "^4.16.0", "matrix-mock-request": "^2.5.0", - "matrix-web-i18n": "^3.1.2", + "matrix-web-i18n": "^3.1.3", "mocha-junit-reporter": "^2.2.0", "node-fetch": "2", "postcss-scss": "^4.0.4", diff --git a/yarn.lock b/yarn.lock index 0dc0958be63..9779c881b22 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7677,10 +7677,10 @@ matrix-mock-request@^2.5.0: dependencies: expect "^28.1.0" -matrix-web-i18n@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/matrix-web-i18n/-/matrix-web-i18n-3.1.2.tgz#c5a51516dc5379688875f377ee03e34f91b91624" - integrity sha512-HBqpjkR9jMPEVq4WuAwDNTkgME85EDstVCyaeaEDmFYpo1FclMDSeXnZgj3FM3RKNXDRLVHdSo+FA1626JuF6Q== +matrix-web-i18n@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/matrix-web-i18n/-/matrix-web-i18n-3.1.3.tgz#b462015b138ebdd288ed945507abea42c896f52d" + integrity sha512-9JUUTifqS/Xe6YQr5uDbX04xvr5Pxg8aU7tRKx49/ZLqm4dZoJKo4SKpyLEwCQeNjAvjcKuXibWO+2hkZ2/Ojw== dependencies: "@babel/parser" "^7.18.5" "@babel/traverse" "^7.18.5"