intlify / bundle-tools

bundling for intlify i18n tools
MIT License
239 stars 37 forks source link

unplugin-vue-i18n: regression with v0.9.1 - unexpected token: '{' #235

Closed cexbrayat closed 1 year ago

cexbrayat commented 1 year ago

Reporting a bug?

Upgrading projects to v0.9.1 throws an unexpected token: '{' error if the createI18n code looks like this:

const numberFormats = {
  en: {
    currency: {
      style: 'currency',
      currency: 'USD',
    },
  },
} as const;

const i18n = createI18n<[typeof en], 'en'>({
  legacy: false,
  locale: 'en',
  numberFormats,
  messages: {
    en,
  },
});

createApp(App).use(i18n).mount('#app');

Note that numberFormats is defined as a variable. When starting the application, the generated code is buggy and throws an error.

Generated code:

export default {
  "en": {
    "currency": {
      "style": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize(["currency"])};fn.source="currency";return fn;})(),
      "currency": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize(["USD"])};fn.source="USD";return fn;})()
    }
  }
}{
  "legacy": false,
  "locale": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize(["en"])};fn.source="en";return fn;})(),
  "messages": {

  }
}

Note the }{ issue in the generated code

Expected behavior

It should compile properly

Reproduction

https://stackblitz.com/edit/node-ngunqx?file=repro%2Fpackage.json,repro%2Fsrc%2Fmain.ts,repro%2Fsrc%2Fen.json,repro%2Fsrc%2FApp.vue,repro%2Fvite.config.ts

Run

cd repro
npm i
npm run dev

Issue Package

unplugin-vue-i18n

System Info

System:
    OS: macOS 13.1
    CPU: (10) arm64 Apple M1 Max
    Memory: 328.50 MB / 64.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.17.0 - ~/.volta/tools/image/node/16.17.0/bin/node
    Yarn: 1.22.17 - ~/.volta/tools/image/yarn/1.22.17/bin/yarn
    npm: 8.19.3 - ~/.volta/tools/image/npm/8.19.3/bin/npm
  Browsers:
    Chrome: 110.0.5481.177
    Firefox: 110.0
    Safari: 16.2
  npmPackages:
    vite: 4.1.4 => 4.1.4
    vue: 3.2.47 => 3.2.47
    vue-i18n: 9.2.2 => 9.2.2

Screenshot

No response

Additional context

Downgrading to v0.8.2 fixes the issue. It also works if numberFormats is declared inline directly

Validations

kazupon commented 1 year ago

Hi! Thank you for your reproduction! I've just checked it!

It's rare for this issue to occur.

In generally, when we are using vue-i18n, i18n resources should be organized in a directory such as locales or lang. In that case, the include option of unplugin-vue-i18n should be set to include: path.resolve(__dirname, 'src/locales/**'). With that setting, unplugin-vue-i18n will only transform for 'src/locales/**', so you will not have this issue.

But, we should write clearly to docs that we should organize for js and ts format resources.

Tanimodori commented 1 year ago

Same issue encountered here. The part before { is an array. The code transform is buggy in 0.9.1

Tanimodori commented 1 year ago

src/locale/index.ts

import { createI18n } from 'vue-i18n';

export const WHATEVER_THE_FIRST_EXPORT = ['WHATEVER_THE_FIRST_EXPORT'];

const i18n = createI18n({
  locale: 'zh-CN',
  fallbackLocale: 'en-US',
  allowComposition: true,
  messages: {
    'en-US': {},
    'zh-CN': {},
  },
});

export default i18n;

Transformed:

export default [
  (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize(["WHATEVER_THE_FIRST_EXPORT"])};fn.source="WHATEVER_THE_FIRST_EXPORT";return fn;})(),

]{
  "locale": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize(["zh-CN"])};fn.source="zh-CN";return fn;})(),
  "fallbackLocale": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize(["en-US"])};fn.source="en-US";return fn;})(),
  "allowComposition": true,
  "messages": {
    "en-US": {

    },
    "zh-CN": {

    }
  }
}
kazupon commented 1 year ago

Please could you also give us vite.config?

Tanimodori commented 1 year ago

I'll setup a proper reproduction repo for it. Give me a second :)

Tanimodori commented 1 year ago

@kazupon The reproduction is at https://github.com/Tanimodori/unplugin-vue-i18n-regression-repro

Tanimodori commented 1 year ago

The example of @cexbrayat is also causing the error:

import { createI18n } from "vue-i18n";

const en = {};

const i18n = createI18n({
  locale: "en",
  messages: {
    en,
  },
});

export default i18n;
export default {

}{
  "locale": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize(["en"])};fn.source="en";return fn;})(),
  "messages": {

  }
}
kazupon commented 1 year ago

Hi! Thank you for you reproduction repo quickly.

I looked at your vite.config. I see that src/locale/index.ts is now in the transform of i18n resources. I recommend configuring the include option to unplugin-vue-i18n to prevent your application code from being included.

Tanimodori commented 1 year ago

So this is the limitation mentioned at https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n#include

⚠️ NOTE: js and ts resources are limited to simple export (export default) as locale messages object only, such as programmatically dynamic resource construction is not guaranteed to work currently.

v0.8.2 happens to be working and 0.9.1 doesn't.

I'll remove the include in my config since I don't use pre-compile. Thanks for your quick help!

kazupon commented 1 year ago

I've just added the notice docs.

⚠️ NOTE: If you use the js and ts resources formats, set the paths, so your application code is not targeted. We recommend that resources be isolated from the application code.

https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n#include

So, close this issue. Thanks!