Skip to content

Commit 92bfce0

Browse files
committed
perf: merge all namespace of i18n resource in prod
Signed-off-by: Innei <i@innei.in>
1 parent 304cb7f commit 92bfce0

File tree

4 files changed

+72
-39
lines changed

4 files changed

+72
-39
lines changed

configs/vite.render.config.ts

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { readFileSync } from "node:fs"
2-
import { resolve } from "node:path"
1+
import fs, { readFileSync } from "node:fs"
2+
import path, { resolve } from "node:path"
33

44
import * as babel from "@babel/core"
55
import generate from "@babel/generator"
@@ -14,6 +14,51 @@ import { getGitHash } from "../scripts/lib"
1414

1515
const pkg = JSON.parse(readFileSync("package.json", "utf8"))
1616
const isCI = process.env.CI === "true" || process.env.CI === "1"
17+
function localesPlugin(): Plugin {
18+
return {
19+
name: "locales-merge",
20+
enforce: "post",
21+
generateBundle(options, bundle) {
22+
const localesDir = path.resolve(__dirname, "locales")
23+
const namespaces = fs.readdirSync(localesDir)
24+
const languageResources = {}
25+
26+
namespaces.forEach((namespace) => {
27+
const namespacePath = path.join(localesDir, namespace)
28+
const files = fs.readdirSync(namespacePath).filter((file) => file.endsWith(".json"))
29+
30+
files.forEach((file) => {
31+
const lang = path.basename(file, ".json")
32+
const filePath = path.join(namespacePath, file)
33+
const content = JSON.parse(fs.readFileSync(filePath, "utf-8"))
34+
35+
if (!languageResources[lang]) {
36+
languageResources[lang] = {}
37+
}
38+
languageResources[lang][namespace] = content
39+
})
40+
})
41+
42+
Object.entries(languageResources).forEach(([lang, resources]) => {
43+
const fileName = `locales/${lang}.js`
44+
const content = `export default ${JSON.stringify(resources)};`
45+
46+
this.emitFile({
47+
type: "asset",
48+
fileName,
49+
source: content,
50+
})
51+
})
52+
53+
// Remove original JSON chunks
54+
Object.keys(bundle).forEach((key) => {
55+
if (key.startsWith("locales/") && key.endsWith(".json")) {
56+
delete bundle[key]
57+
}
58+
})
59+
},
60+
}
61+
}
1762

1863
export const viteRenderBaseConfig = {
1964
resolve: {
@@ -52,6 +97,7 @@ export const viteRenderBaseConfig = {
5297
},
5398
}),
5499

100+
localesPlugin(),
55101
viteTwToRawString(),
56102

57103
{

src/renderer/src/i18n.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,7 @@ if (import.meta.hot) {
2929
async ({ file, content }: { file: string; content: string }) => {
3030
const resources = JSON.parse(content)
3131
const i18next = jotaiStore.get(i18nAtom)
32-
// `file` is absolute path e.g. /Users/innei/git/follow/locales/en.json
33-
// Absolute path e.g. /Users/innei/git/follow/locales/<module-name>/en.json
34-
35-
// 1. parse root language
36-
// if (!file.includes("locales/namespaces")) {
37-
// const lang = file.split("/").pop()?.replace(".json", "")
38-
// if (!lang) return
39-
// i18next.addResourceBundle(lang, defaultNS, resources, true, true)
40-
// i18next.reloadResources(lang, defaultNS)
41-
// } else {
32+
4233
const nsName = file.match(/locales\/(.+?)\//)?.[1]
4334

4435
if (!nsName) return
@@ -48,7 +39,6 @@ if (import.meta.hot) {
4839

4940
console.info("reload", lang, nsName)
5041
await i18next.reloadResources(lang, nsName)
51-
// }
5242

5343
import.meta.env.DEV && EventBus.dispatch("I18N_UPDATE", "")
5444
},

src/renderer/src/providers/i18n-provider.tsx

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -42,37 +42,35 @@ const langChangedHandler = async (lang: string) => {
4242

4343
loadingLangLock.add(lang)
4444

45-
const nsGlobbyMap = import.meta.glob("@locales/*/*.json")
45+
if (import.meta.env.DEV) {
46+
const nsGlobbyMap = import.meta.glob("@locales/*/*.json")
4647

47-
// const rootGlobbyMap = import.meta.glob("@locales/*.json")
48-
// const rootResources = await rootGlobbyMap[`../../locales/${lang}.json`]()
49-
// .then((m: any) => m.default)
50-
// .catch(() => {
51-
// toast.error(`${t("common:tips.load-lng-error")}: ${lang}`)
52-
// })
53-
// i18next.addResourceBundle(lang, defaultNS, rootResources, true, true)
48+
const namespaces = Object.keys(defaultResources.en)
5449

55-
const namespaces = Object.keys(defaultResources.en)
50+
const res = await Promise.allSettled(
51+
namespaces.map(async (ns) => {
52+
const loader = nsGlobbyMap[`../../locales/${ns}/${lang}.json`]
5653

57-
const res = await Promise.allSettled(
58-
namespaces.map(async (ns) => {
59-
// if (ns === defaultNS) return
54+
if (!loader) return
55+
const nsResources = await loader().then((m: any) => m.default)
6056

61-
const loader = nsGlobbyMap[`../../locales/${ns}/${lang}.json`]
62-
63-
if (!loader) return
64-
const nsResources = await loader().then((m: any) => m.default)
57+
i18next.addResourceBundle(lang, ns, nsResources, true, true)
58+
}),
59+
)
6560

66-
i18next.addResourceBundle(lang, ns, nsResources, true, true)
67-
}),
68-
)
61+
for (const r of res) {
62+
if (r.status === "rejected") {
63+
toast.error(`${t("common:tips.load-lng-error")}: ${lang}`)
64+
loadingLangLock.delete(lang)
6965

70-
for (const r of res) {
71-
if (r.status === "rejected") {
72-
toast.error(`${t("common:tips.load-lng-error")}: ${lang}`)
73-
loadingLangLock.delete(lang)
66+
return
67+
}
68+
}
69+
} else {
70+
const res = await eval(`import('/locales/${lang}.js').then((res) => res?.default || res)`)
7471

75-
return
72+
for (const namespace in res) {
73+
i18next.addResourceBundle(lang, namespace, res[namespace], true, true)
7674
}
7775
}
7876

vite.config.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export default ({ mode }) => {
7979
__debug_proxy: resolve(ROOT, "/__debug_proxy.html"),
8080
},
8181
output: {
82-
experimentalMinChunkSize: 500_000,
82+
// experimentalMinChunkSize: 500_000,
8383
},
8484
},
8585
},
@@ -97,7 +97,6 @@ export default ({ mode }) => {
9797
}),
9898
htmlPlugin(typedEnv),
9999
mkcert(),
100-
101100
devPrint(),
102101

103102
process.env.ANALYZER && analyzer(),

0 commit comments

Comments
 (0)