From 101895b02e314e7a99dba7e6bc5aedd7fc8c5e0b Mon Sep 17 00:00:00 2001 From: Moritz Vetter <16950410+Isokaeder@users.noreply.github.com> Date: Tue, 23 Jul 2024 09:36:52 +0200 Subject: [PATCH] fix(element-ui): don't externalyize translations create helper function to handle eventual default keys when importing element-ui's translation objects --- packages/kotti-ui/source/kotti-i18n/hooks.ts | 63 +++++++++++++++----- packages/kotti-ui/vite.config.ts | 2 +- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/packages/kotti-ui/source/kotti-i18n/hooks.ts b/packages/kotti-ui/source/kotti-i18n/hooks.ts index a137d8189f..6a874a2514 100644 --- a/packages/kotti-ui/source/kotti-i18n/hooks.ts +++ b/packages/kotti-ui/source/kotti-i18n/hooks.ts @@ -1,9 +1,4 @@ import elementLocale from 'element-ui/lib/locale/index.js' -import elementDe from 'element-ui/lib/locale/lang/de.js' -import elementEn from 'element-ui/lib/locale/lang/en.js' -import elementEs from 'element-ui/lib/locale/lang/es.js' -import elementFr from 'element-ui/lib/locale/lang/fr.js' -import elementJa from 'element-ui/lib/locale/lang/ja.js' import type { Ref, UnwrapRef } from 'vue' import { computed, inject, provide, reactive, watch } from 'vue' @@ -59,6 +54,35 @@ export const useTranslationNamespace = ( return computed(() => context.messages[namespace]) } +interface DefaultObject> { + default: DefaultObject | R +} + +/** + * HACK: This function works around a CJS/ESM/EsModule interop issue. + * + * The objects we import at `element-ui/lib/locale/lang/[a-z]{2}.js` are EsModules + * (exports.__esModule = true). Due to current javascript flavour shenanigans, + * the imported object that we need can be found at the root, at the `.default` key, + * or even at the `.default.default` key. + * To mitigate we iterate down the potential default chain until we arrive at the + * right position. + */ +const accessDefaultKey = >( + obj: DefaultObject, +): R => { + if (!('default' in obj)) return obj + + let current: DefaultObject | R = obj + for (let i = 0; i < 10; i++) { + current = current.default as DefaultObject | R + if (!('default' in current)) { + return current + } + } + throw new Error('accessDefaultKey: could not exhaust nested default keys') +} + /** * Provides the translation context to child components */ @@ -89,19 +113,26 @@ export const useI18nProvide = ({ */ watch( locale, - (newValue) => { - const elementUiTranslations = { - 'en-US': elementEn, - 'de-DE': elementDe, - 'es-ES': elementEs, - 'fr-FR': elementFr, - 'ja-JP': elementJa, - }[newValue] + async (newValue) => { + try { + const elementUiTranslations = await { + /* eslint-disable @typescript-eslint/naming-convention */ + 'en-US': () => import('element-ui/lib/locale/lang/en.js'), + 'de-DE': () => import('element-ui/lib/locale/lang/de.js'), + 'es-ES': () => import('element-ui/lib/locale/lang/es.js'), + 'fr-FR': () => import('element-ui/lib/locale/lang/fr.js'), + 'ja-JP': () => import('element-ui/lib/locale/lang/ja.js'), + /* eslint-enable @typescript-eslint/naming-convention */ + }[newValue]() - if ('default' in elementUiTranslations) - throw new Error('Detected Broken Build') + const resolvedEsModuleInterop = accessDefaultKey(elementUiTranslations) - elementLocale.use(elementUiTranslations) + elementLocale.use(resolvedEsModuleInterop) + } catch (error) { + // eslint-disable-next-line no-console + console.error(error) + throw error + } }, { immediate: true, flush: 'post' }, ) diff --git a/packages/kotti-ui/vite.config.ts b/packages/kotti-ui/vite.config.ts index e81cdb5b88..cfeaeb58ae 100644 --- a/packages/kotti-ui/vite.config.ts +++ b/packages/kotti-ui/vite.config.ts @@ -56,7 +56,7 @@ export default defineConfig(({ mode }) => { const external = [ ...Object.keys(packageJSON.peerDependencies), ...Object.keys(packageJSON.dependencies), - /.*element-ui\/lib\/date-picker.js.*/, + /.*element-ui.*/, /.*tippy\.js.*/, /lodash\/.*/, /vue\/.*/,