diff --git a/foundations/core/packages/analytics/src/index.ts b/foundations/core/packages/analytics/src/index.ts index 31f28b4a02..daa893f2d4 100644 --- a/foundations/core/packages/analytics/src/index.ts +++ b/foundations/core/packages/analytics/src/index.ts @@ -78,7 +78,8 @@ export const Analytics = { addEventListener(PlatformEvent, async (_event, _status: Status) => { if (_status.severity === Severity.ERROR) { - const label = await translate(_status.code, _status.params, 'en') + // Skip error broadcast in translate to avoid infinite loop + const label = await translate(_status.code, _status.params, 'en', true) Analytics.handleError(new Error(label)) } }) diff --git a/foundations/core/packages/api-client/src/client.ts b/foundations/core/packages/api-client/src/client.ts index 118fde1760..ab3eb5a7f8 100644 --- a/foundations/core/packages/api-client/src/client.ts +++ b/foundations/core/packages/api-client/src/client.ts @@ -88,7 +88,16 @@ async function createClient ( config: ServerConfig, options: ConnectOptions ): Promise { - addLocation(clientId, () => import(/* webpackChunkName: "client" */ '@hcengineering/client-resources')) + addLocation(clientId, () => { + // In Node/Jest environments, dynamic import callbacks can fail without + // --experimental-vm-modules. Use require there and keep dynamic import + // for browser/bundler environments. + if (typeof window === 'undefined') { + // eslint-disable-next-line @typescript-eslint/no-var-requires + return Promise.resolve(require('@hcengineering/client-resources')) + } + return import(/* webpackChunkName: "client" */ '@hcengineering/client-resources') + }) const { socketFactory, connectionTimeout } = options diff --git a/foundations/core/packages/platform/src/i18n.ts b/foundations/core/packages/platform/src/i18n.ts index 4534f01139..a5cab62511 100644 --- a/foundations/core/packages/platform/src/i18n.ts +++ b/foundations/core/packages/platform/src/i18n.ts @@ -64,11 +64,21 @@ export async function loadPluginStrings (locale: string, force: boolean = false) } } -async function loadTranslationsForComponent (plugin: Plugin, locale: string): Promise { +async function setStatus (status: Status, skipError?: boolean): Promise { + if (skipError !== true) { + await setPlatformStatus(status) + } +} + +async function loadTranslationsForComponent ( + plugin: Plugin, + locale: string, + skipError?: boolean +): Promise { const loader = loaders.get(plugin) if (loader === undefined) { const status = new Status(Severity.ERROR, platform.status.NoLoaderForStrings, { plugin }) - await setPlatformStatus(status) + await setStatus(status, skipError) return status } try { @@ -79,7 +89,7 @@ async function loadTranslationsForComponent (plugin: Plugin, locale: string): Pr return (await loader('en')) as Record | Status } catch (err: any) { const status = unknownError(err) - await setPlatformStatus(status) + await setStatus(status, skipError) return status } } @@ -104,7 +114,11 @@ function getCachedTranslation (id: _IdInfo, locale: string): IntlString | Status } } -async function getTranslation (id: _IdInfo, locale: string): Promise { +async function getTranslation ( + id: _IdInfo, + locale: string, + skipError?: boolean +): Promise { try { const localtTanslations = translations.get(locale) ?? new Map>() if (!translations.has(locale)) { @@ -112,7 +126,7 @@ async function getTranslation (id: _IdInfo, locale: string): Promise> ( message: IntlString

, params: P, - language?: string + language?: string, + skipError?: boolean ): Promise { const locale = language ?? getMetadata(platform.metadata.locale) ?? 'en' const localCache = cache.get(locale) ?? new Map() @@ -171,7 +186,7 @@ export async function translate

> ( if (id.component === _EmbeddedId) { return id.name } - const translation = getCachedTranslation(id, locale) ?? (await getTranslation(id, locale)) ?? message + const translation = getCachedTranslation(id, locale) ?? (await getTranslation(id, locale, skipError)) ?? message if (translation instanceof Status) { localCache.set(message, translation) return message @@ -181,7 +196,7 @@ export async function translate

> ( return compiled.format(params) } catch (err) { const status = unknownError(err) - void setPlatformStatus(status) + await setStatus(status, skipError) localCache.set(message, status) return message } @@ -194,7 +209,8 @@ export function translateCB

> ( message: IntlString

, params: P, language: string | undefined, - resolve: (value: string) => void + resolve: (value: string) => void, + skipError?: boolean ): void { const locale = language ?? getMetadata(platform.metadata.locale) ?? 'en' const localCache = cache.get(locale) ?? new Map() @@ -219,7 +235,7 @@ export function translateCB

> ( } } catch (err) { const status = unknownError(err) - void setPlatformStatus(status) + void setStatus(status, skipError) localCache.set(message, status) resolve(message) return @@ -232,7 +248,7 @@ export function translateCB

> ( }) .catch((err) => { const status = unknownError(err) - void setPlatformStatus(status) + void setStatus(status, skipError) localCache.set(message, status) resolve(message) })