@intlify/unplugin-vue-i18n 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -225,6 +225,8 @@ export default defineConfig({
225
225
  ],
226
226
  })
227
227
  ```
228
+ unplugin-vue-i18n will automatically merge locale files into `@intlify/unplugin-vue-i18n/messages`. This allows locales to be split across multiple files, for example `src/locales/fruits/en.json` and `src/locales/vegetables/en.json`.
229
+
228
230
  ### Types
229
231
 
230
232
  If you want type definition of `@intlify/unplugin-vue-i18n/messages`, add `unplugin-vue-i18n/messages` to `compilerOptions.types` of your tsconfig:
@@ -377,6 +379,16 @@ This option works with vue-i18n v9.3 and later.
377
379
  > ⚠️ NOTE:
378
380
  If you enable this option, **you should check resources in your application are pre-compiled with this plugin.** If you will be loading resources dynamically from the back-end via the API, enabling this option do not work because there is not message compiler.
379
381
 
382
+ ### `ssr`
383
+
384
+ - **Type:** `boolean`
385
+ - **Default:** `false`
386
+
387
+ Whether to bundle vue-i18n module for SSR at build time
388
+
389
+ > ⚠️ NOTE:
390
+ This option works with vue-i18n v9.4 and later.
391
+
380
392
  ### `runtimeOnly`
381
393
 
382
394
  - **Type:** `boolean`
package/lib/index.cjs CHANGED
@@ -141,6 +141,8 @@ const unplugin = unplugin$1.createUnplugin((options = {}, meta) => {
141
141
  debug("compositionOnly", compositionOnly);
142
142
  const fullInstall = installedPkg === "vue-i18n" ? shared.isBoolean(options.fullInstall) ? options.fullInstall : true : false;
143
143
  debug("fullInstall", fullInstall);
144
+ const ssrBuild = !!options.ssr;
145
+ debug("ssr", ssrBuild);
144
146
  const useVueI18nImportName = options.useVueI18nImportName;
145
147
  if (useVueI18nImportName != null) {
146
148
  warn(`'useVueI18nImportName' option is experimental`);
@@ -148,7 +150,9 @@ const unplugin = unplugin$1.createUnplugin((options = {}, meta) => {
148
150
  debug("useVueI18nImportName", useVueI18nImportName);
149
151
  const getVueI18nAliasName = () => vueI18nVersion === "9" || vueI18nVersion === "8" ? "vue-i18n" : vueI18nVersion === "unknown" && installedPkg === "petite-vue-i18n" && shared.isBoolean(useVueI18nImportName) && useVueI18nImportName ? "vue-i18n" : installedPkg;
150
152
  const getVueI18nBridgeAliasPath = () => `vue-i18n-bridge/dist/vue-i18n-bridge.runtime.esm-bundler.js`;
151
- const getVueI18nAliasPath = (aliasName) => vueI18nVersion === "8" ? `${aliasName}/dist/${aliasName}.esm.js` : `${aliasName}/dist/${installedPkg}.runtime.esm-bundler.js`;
153
+ const getVueI18nAliasPath = (aliasName, { ssr = false, runtimeOnly: runtimeOnly2 = false }) => {
154
+ return vueI18nVersion === "8" ? `${aliasName}/dist/${aliasName}.esm.js` : `${aliasName}/dist/${installedPkg}${runtimeOnly2 ? ".runtime" : ""}.${!ssr ? "esm-bundler.js" : "node.mjs"}`;
155
+ };
152
156
  const esm = shared.isBoolean(options.esm) ? options.esm : true;
153
157
  debug("esm", esm);
154
158
  const allowDynamic = !!options.allowDynamic;
@@ -177,12 +181,15 @@ const unplugin = unplugin$1.createUnplugin((options = {}, meta) => {
177
181
  config.resolve,
178
182
  meta.framework
179
183
  );
180
- if (command === "build" && runtimeOnly) {
184
+ if (command === "build") {
181
185
  debug(`vue-i18n alias name: ${vueI18nAliasName}`);
182
186
  if (shared.isArray(config.resolve.alias)) {
183
187
  config.resolve.alias.push({
184
188
  find: vueI18nAliasName,
185
- replacement: getVueI18nAliasPath(vueI18nAliasName)
189
+ replacement: getVueI18nAliasPath(vueI18nAliasName, {
190
+ ssr: ssrBuild,
191
+ runtimeOnly
192
+ })
186
193
  });
187
194
  if (installedVueI18nBridge) {
188
195
  config.resolve.alias.push({
@@ -191,14 +198,21 @@ const unplugin = unplugin$1.createUnplugin((options = {}, meta) => {
191
198
  });
192
199
  }
193
200
  } else if (shared.isObject(config.resolve.alias)) {
194
- config.resolve.alias[vueI18nAliasName] = getVueI18nAliasPath(vueI18nAliasName);
201
+ config.resolve.alias[vueI18nAliasName] = getVueI18nAliasPath(vueI18nAliasName, {
202
+ ssr: ssrBuild,
203
+ runtimeOnly
204
+ });
195
205
  if (installedVueI18nBridge) {
196
206
  config.resolve.alias["vue-i18n-bridge"] = getVueI18nBridgeAliasPath();
197
207
  }
198
208
  }
199
209
  debug(
200
210
  `set ${vueI18nAliasName} runtime only: ${getVueI18nAliasPath(
201
- vueI18nAliasName
211
+ vueI18nAliasName,
212
+ {
213
+ ssr: ssrBuild,
214
+ runtimeOnly
215
+ }
202
216
  )}`
203
217
  );
204
218
  if (installedVueI18nBridge) {
@@ -341,15 +355,19 @@ const unplugin = unplugin$1.createUnplugin((options = {}, meta) => {
341
355
  compiler.options.resolve,
342
356
  meta.framework
343
357
  );
344
- if (isProduction && runtimeOnly) {
345
- compiler.options.resolve.alias[vueI18nAliasName] = getVueI18nAliasPath(vueI18nAliasName);
358
+ if (isProduction) {
359
+ compiler.options.resolve.alias[vueI18nAliasName] = getVueI18nAliasPath(vueI18nAliasName, {
360
+ ssr: ssrBuild,
361
+ runtimeOnly
362
+ });
346
363
  if (installedVueI18nBridge) {
347
364
  compiler.options.resolve.alias["vue-i18n-bridge"] = getVueI18nBridgeAliasPath();
348
365
  }
349
366
  debug(
350
- `set ${vueI18nAliasName} runtime only: ${getVueI18nAliasPath(
351
- vueI18nAliasName
352
- )}`
367
+ `set ${vueI18nAliasName}: ${getVueI18nAliasPath(vueI18nAliasName, {
368
+ ssr: ssrBuild,
369
+ runtimeOnly
370
+ })}`
353
371
  );
354
372
  if (installedVueI18nBridge) {
355
373
  debug(
@@ -611,10 +629,29 @@ async function generateBundleResources(resources, query, isProduction, {
611
629
  codes.push(`${JSON.stringify(name)}: ${code}`);
612
630
  }
613
631
  }
614
- return `export default {
615
- ${codes.join(`,
616
- `)}
617
- }`;
632
+ return `const isObject = (item) => item && typeof item === 'object' && !Array.isArray(item);
633
+
634
+ const mergeDeep = (target, ...sources) => {
635
+ if (!sources.length) return target;
636
+ const source = sources.shift();
637
+
638
+ if (isObject(target) && isObject(source)) {
639
+ for (const key in source) {
640
+ if (isObject(source[key])) {
641
+ if (!target[key]) Object.assign(target, { [key]: {} });
642
+ mergeDeep(target[key], source[key]);
643
+ } else {
644
+ Object.assign(target, { [key]: source[key] });
645
+ }
646
+ }
647
+ }
648
+
649
+ return mergeDeep(target, ...sources);
650
+ }
651
+
652
+ export default mergeDeep({},
653
+ ${codes.map((code) => `{${code}}`).join(",\n")}
654
+ );`;
618
655
  }
619
656
  async function getCode(source, filename, sourceMap, query, framework = "vite") {
620
657
  const { index, issuerPath } = query;
package/lib/index.mjs CHANGED
@@ -129,6 +129,8 @@ const unplugin = createUnplugin((options = {}, meta) => {
129
129
  debug("compositionOnly", compositionOnly);
130
130
  const fullInstall = installedPkg === "vue-i18n" ? isBoolean(options.fullInstall) ? options.fullInstall : true : false;
131
131
  debug("fullInstall", fullInstall);
132
+ const ssrBuild = !!options.ssr;
133
+ debug("ssr", ssrBuild);
132
134
  const useVueI18nImportName = options.useVueI18nImportName;
133
135
  if (useVueI18nImportName != null) {
134
136
  warn(`'useVueI18nImportName' option is experimental`);
@@ -136,7 +138,9 @@ const unplugin = createUnplugin((options = {}, meta) => {
136
138
  debug("useVueI18nImportName", useVueI18nImportName);
137
139
  const getVueI18nAliasName = () => vueI18nVersion === "9" || vueI18nVersion === "8" ? "vue-i18n" : vueI18nVersion === "unknown" && installedPkg === "petite-vue-i18n" && isBoolean(useVueI18nImportName) && useVueI18nImportName ? "vue-i18n" : installedPkg;
138
140
  const getVueI18nBridgeAliasPath = () => `vue-i18n-bridge/dist/vue-i18n-bridge.runtime.esm-bundler.js`;
139
- const getVueI18nAliasPath = (aliasName) => vueI18nVersion === "8" ? `${aliasName}/dist/${aliasName}.esm.js` : `${aliasName}/dist/${installedPkg}.runtime.esm-bundler.js`;
141
+ const getVueI18nAliasPath = (aliasName, { ssr = false, runtimeOnly: runtimeOnly2 = false }) => {
142
+ return vueI18nVersion === "8" ? `${aliasName}/dist/${aliasName}.esm.js` : `${aliasName}/dist/${installedPkg}${runtimeOnly2 ? ".runtime" : ""}.${!ssr ? "esm-bundler.js" : "node.mjs"}`;
143
+ };
140
144
  const esm = isBoolean(options.esm) ? options.esm : true;
141
145
  debug("esm", esm);
142
146
  const allowDynamic = !!options.allowDynamic;
@@ -165,12 +169,15 @@ const unplugin = createUnplugin((options = {}, meta) => {
165
169
  config.resolve,
166
170
  meta.framework
167
171
  );
168
- if (command === "build" && runtimeOnly) {
172
+ if (command === "build") {
169
173
  debug(`vue-i18n alias name: ${vueI18nAliasName}`);
170
174
  if (isArray(config.resolve.alias)) {
171
175
  config.resolve.alias.push({
172
176
  find: vueI18nAliasName,
173
- replacement: getVueI18nAliasPath(vueI18nAliasName)
177
+ replacement: getVueI18nAliasPath(vueI18nAliasName, {
178
+ ssr: ssrBuild,
179
+ runtimeOnly
180
+ })
174
181
  });
175
182
  if (installedVueI18nBridge) {
176
183
  config.resolve.alias.push({
@@ -179,14 +186,21 @@ const unplugin = createUnplugin((options = {}, meta) => {
179
186
  });
180
187
  }
181
188
  } else if (isObject(config.resolve.alias)) {
182
- config.resolve.alias[vueI18nAliasName] = getVueI18nAliasPath(vueI18nAliasName);
189
+ config.resolve.alias[vueI18nAliasName] = getVueI18nAliasPath(vueI18nAliasName, {
190
+ ssr: ssrBuild,
191
+ runtimeOnly
192
+ });
183
193
  if (installedVueI18nBridge) {
184
194
  config.resolve.alias["vue-i18n-bridge"] = getVueI18nBridgeAliasPath();
185
195
  }
186
196
  }
187
197
  debug(
188
198
  `set ${vueI18nAliasName} runtime only: ${getVueI18nAliasPath(
189
- vueI18nAliasName
199
+ vueI18nAliasName,
200
+ {
201
+ ssr: ssrBuild,
202
+ runtimeOnly
203
+ }
190
204
  )}`
191
205
  );
192
206
  if (installedVueI18nBridge) {
@@ -329,15 +343,19 @@ const unplugin = createUnplugin((options = {}, meta) => {
329
343
  compiler.options.resolve,
330
344
  meta.framework
331
345
  );
332
- if (isProduction && runtimeOnly) {
333
- compiler.options.resolve.alias[vueI18nAliasName] = getVueI18nAliasPath(vueI18nAliasName);
346
+ if (isProduction) {
347
+ compiler.options.resolve.alias[vueI18nAliasName] = getVueI18nAliasPath(vueI18nAliasName, {
348
+ ssr: ssrBuild,
349
+ runtimeOnly
350
+ });
334
351
  if (installedVueI18nBridge) {
335
352
  compiler.options.resolve.alias["vue-i18n-bridge"] = getVueI18nBridgeAliasPath();
336
353
  }
337
354
  debug(
338
- `set ${vueI18nAliasName} runtime only: ${getVueI18nAliasPath(
339
- vueI18nAliasName
340
- )}`
355
+ `set ${vueI18nAliasName}: ${getVueI18nAliasPath(vueI18nAliasName, {
356
+ ssr: ssrBuild,
357
+ runtimeOnly
358
+ })}`
341
359
  );
342
360
  if (installedVueI18nBridge) {
343
361
  debug(
@@ -599,10 +617,29 @@ async function generateBundleResources(resources, query, isProduction, {
599
617
  codes.push(`${JSON.stringify(name)}: ${code}`);
600
618
  }
601
619
  }
602
- return `export default {
603
- ${codes.join(`,
604
- `)}
605
- }`;
620
+ return `const isObject = (item) => item && typeof item === 'object' && !Array.isArray(item);
621
+
622
+ const mergeDeep = (target, ...sources) => {
623
+ if (!sources.length) return target;
624
+ const source = sources.shift();
625
+
626
+ if (isObject(target) && isObject(source)) {
627
+ for (const key in source) {
628
+ if (isObject(source[key])) {
629
+ if (!target[key]) Object.assign(target, { [key]: {} });
630
+ mergeDeep(target[key], source[key]);
631
+ } else {
632
+ Object.assign(target, { [key]: source[key] });
633
+ }
634
+ }
635
+ }
636
+
637
+ return mergeDeep(target, ...sources);
638
+ }
639
+
640
+ export default mergeDeep({},
641
+ ${codes.map((code) => `{${code}}`).join(",\n")}
642
+ );`;
606
643
  }
607
644
  async function getCode(source, filename, sourceMap, query, framework = "vite") {
608
645
  const { index, issuerPath } = query;
package/lib/types.d.cts CHANGED
@@ -7,6 +7,7 @@ interface PluginOptions {
7
7
  dropMessageCompiler?: boolean;
8
8
  runtimeOnly?: boolean;
9
9
  compositionOnly?: boolean;
10
+ ssr?: boolean;
10
11
  fullInstall?: boolean;
11
12
  esm?: boolean;
12
13
  forceStringify?: boolean;
package/lib/types.d.mts CHANGED
@@ -7,6 +7,7 @@ interface PluginOptions {
7
7
  dropMessageCompiler?: boolean;
8
8
  runtimeOnly?: boolean;
9
9
  compositionOnly?: boolean;
10
+ ssr?: boolean;
10
11
  fullInstall?: boolean;
11
12
  esm?: boolean;
12
13
  forceStringify?: boolean;
package/lib/types.d.ts CHANGED
@@ -7,6 +7,7 @@ interface PluginOptions {
7
7
  dropMessageCompiler?: boolean;
8
8
  runtimeOnly?: boolean;
9
9
  compositionOnly?: boolean;
10
+ ssr?: boolean;
10
11
  fullInstall?: boolean;
11
12
  esm?: boolean;
12
13
  forceStringify?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlify/unplugin-vue-i18n",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "unplugin for Vue I18n",
5
5
  "author": {
6
6
  "name": "kazuya kawaguchi",