diff --git a/configs/vite.render.config.ts b/configs/vite.render.config.ts index aa5949d1a..fe4cba876 100644 --- a/configs/vite.render.config.ts +++ b/configs/vite.render.config.ts @@ -1,5 +1,5 @@ -import { readFileSync } from "node:fs" -import { resolve } from "node:path" +import fs, { readFileSync } from "node:fs" +import path, { resolve } from "node:path" import * as babel from "@babel/core" import generate from "@babel/generator" @@ -14,6 +14,51 @@ import { getGitHash } from "../scripts/lib" const pkg = JSON.parse(readFileSync("package.json", "utf8")) const isCI = process.env.CI === "true" || process.env.CI === "1" +function localesPlugin(): Plugin { + return { + name: "locales-merge", + enforce: "post", + generateBundle(options, bundle) { + const localesDir = path.resolve(__dirname, "locales") + const namespaces = fs.readdirSync(localesDir) + const languageResources = {} + + namespaces.forEach((namespace) => { + const namespacePath = path.join(localesDir, namespace) + const files = fs.readdirSync(namespacePath).filter((file) => file.endsWith(".json")) + + files.forEach((file) => { + const lang = path.basename(file, ".json") + const filePath = path.join(namespacePath, file) + const content = JSON.parse(fs.readFileSync(filePath, "utf-8")) + + if (!languageResources[lang]) { + languageResources[lang] = {} + } + languageResources[lang][namespace] = content + }) + }) + + Object.entries(languageResources).forEach(([lang, resources]) => { + const fileName = `locales/${lang}.js` + const content = `export default ${JSON.stringify(resources)};` + + this.emitFile({ + type: "asset", + fileName, + source: content, + }) + }) + + // Remove original JSON chunks + Object.keys(bundle).forEach((key) => { + if (key.startsWith("locales/") && key.endsWith(".json")) { + delete bundle[key] + } + }) + }, + } +} export const viteRenderBaseConfig = { resolve: { @@ -52,6 +97,7 @@ export const viteRenderBaseConfig = { }, }), + localesPlugin(), viteTwToRawString(), { diff --git a/src/renderer/src/i18n.ts b/src/renderer/src/i18n.ts index 99c280b7b..3c541f805 100644 --- a/src/renderer/src/i18n.ts +++ b/src/renderer/src/i18n.ts @@ -29,16 +29,7 @@ if (import.meta.hot) { async ({ file, content }: { file: string; content: string }) => { const resources = JSON.parse(content) const i18next = jotaiStore.get(i18nAtom) - // `file` is absolute path e.g. /Users/innei/git/follow/locales/en.json - // Absolute path e.g. /Users/innei/git/follow/locales//en.json - // 1. parse root language - // if (!file.includes("locales/namespaces")) { - // const lang = file.split("/").pop()?.replace(".json", "") - // if (!lang) return - // i18next.addResourceBundle(lang, defaultNS, resources, true, true) - // i18next.reloadResources(lang, defaultNS) - // } else { const nsName = file.match(/locales\/(.+?)\//)?.[1] if (!nsName) return @@ -48,7 +39,6 @@ if (import.meta.hot) { console.info("reload", lang, nsName) await i18next.reloadResources(lang, nsName) - // } import.meta.env.DEV && EventBus.dispatch("I18N_UPDATE", "") }, diff --git a/src/renderer/src/providers/i18n-provider.tsx b/src/renderer/src/providers/i18n-provider.tsx index 665212a10..61086b8fc 100644 --- a/src/renderer/src/providers/i18n-provider.tsx +++ b/src/renderer/src/providers/i18n-provider.tsx @@ -42,37 +42,35 @@ const langChangedHandler = async (lang: string) => { loadingLangLock.add(lang) - const nsGlobbyMap = import.meta.glob("@locales/*/*.json") + if (import.meta.env.DEV) { + const nsGlobbyMap = import.meta.glob("@locales/*/*.json") - // const rootGlobbyMap = import.meta.glob("@locales/*.json") - // const rootResources = await rootGlobbyMap[`../../locales/${lang}.json`]() - // .then((m: any) => m.default) - // .catch(() => { - // toast.error(`${t("common:tips.load-lng-error")}: ${lang}`) - // }) - // i18next.addResourceBundle(lang, defaultNS, rootResources, true, true) + const namespaces = Object.keys(defaultResources.en) - const namespaces = Object.keys(defaultResources.en) + const res = await Promise.allSettled( + namespaces.map(async (ns) => { + const loader = nsGlobbyMap[`../../locales/${ns}/${lang}.json`] - const res = await Promise.allSettled( - namespaces.map(async (ns) => { - // if (ns === defaultNS) return + if (!loader) return + const nsResources = await loader().then((m: any) => m.default) - const loader = nsGlobbyMap[`../../locales/${ns}/${lang}.json`] + i18next.addResourceBundle(lang, ns, nsResources, true, true) + }), + ) - if (!loader) return - const nsResources = await loader().then((m: any) => m.default) + for (const r of res) { + if (r.status === "rejected") { + toast.error(`${t("common:tips.load-lng-error")}: ${lang}`) + loadingLangLock.delete(lang) - i18next.addResourceBundle(lang, ns, nsResources, true, true) - }), - ) + return + } + } + } else { + const res = await eval(`import('/locales/${lang}.js').then((res) => res?.default || res)`) - for (const r of res) { - if (r.status === "rejected") { - toast.error(`${t("common:tips.load-lng-error")}: ${lang}`) - loadingLangLock.delete(lang) - - return + for (const namespace in res) { + i18next.addResourceBundle(lang, namespace, res[namespace], true, true) } } diff --git a/vite.config.ts b/vite.config.ts index 4186f4194..86b395048 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -79,7 +79,7 @@ export default ({ mode }) => { __debug_proxy: resolve(ROOT, "/__debug_proxy.html"), }, output: { - experimentalMinChunkSize: 500_000, + // experimentalMinChunkSize: 500_000, }, }, }, @@ -97,7 +97,6 @@ export default ({ mode }) => { }), htmlPlugin(typedEnv), mkcert(), - devPrint(), process.env.ANALYZER && analyzer(),