Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ env:

jobs:
test:
name: 'Test on Node.js ${{ matrix.node }} OS: ${{matrix.os}}'
name: 'Test on Node.js ${{ matrix.node }} OS: ${{matrix.os}} (${{ matrix.framework }})'
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
node: [18, 20, 22]
framework: ['vite', 'rspack', 'webpack']
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down Expand Up @@ -58,3 +59,5 @@ jobs:

- name: Testing
run: pnpm test
env:
TEST_FRAMEWORK: ${{ matrix.framework }}
13 changes: 13 additions & 0 deletions examples/rspack/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>unplugin-vue-i18n example for rspack</title>
</head>
<body>
<div id="app">
<App />
</div>
<script src="/dist/main.js"></script>
</body>
</html>
71 changes: 71 additions & 0 deletions examples/rspack/rspack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// @ts-check
const path = require('path')
const { VueLoaderPlugin } = require('vue-loader')
const VueI18nPlugin = require('../../packages/unplugin-vue-i18n/lib/rspack.cjs')

function transformI18nBlock(source) {
const sourceCopy = source
const block = JSON.parse(
sourceCopy.replace(/[\n\s]/g, '').replace(/,\]$/, ']')
)
if (Array.isArray(block)) {
const transformedBlock = JSON.stringify({
en: {
language: 'Language',
hello: 'hello, world!'
},
ja: {
language: '言語',
hello: 'こんにちは、世界!'
}
})
return transformedBlock
}
return source
}

/**
* @type {import('@rspack/core').RspackOptions}
**/
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: path.resolve(__dirname, './src/main.js'),
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
publicPath: '/dist/'
},
resolve: {
alias: {
vue: path.resolve(
__dirname,
'../../node_modules/vue/dist/vue.esm-bundler.js'
)
}
},
devServer: {
static: {
directory: path.join(__dirname, './')
}
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
loader: 'babel-loader'
}
]
},
plugins: [
new VueLoaderPlugin(),
VueI18nPlugin({
include: [path.resolve(__dirname, './src/locales/**')],
transformI18nBlock: transformI18nBlock
})
]
}
46 changes: 46 additions & 0 deletions examples/rspack/src/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<template>
<form>
<label>{{ t('language') }}</label>
<select v-model="locale">
<option value="en">en</option>
<option value="ja">ja</option>
</select>
</form>
<p>{{ t('hello') }}</p>
<Banana />
<Apple />
</template>

<script>
import { useI18n } from 'vue-i18n'
import Apple from './Apple.vue'
import Banana from './Banana.vue'

export default {
name: 'App',
components: {
Apple,
Banana
},
setup() {
const { t, locale } = useI18n({
inheritLocale: true,
useScope: 'local'
})
return { t, locale }
}
}
</script>

<i18n>
{
"en": {
"language": "Language",
"hello": "hello, world!"
},
"ja": {
"language": "言語",
"hello": "こんにちは、世界!"
}
}
</i18n>
26 changes: 26 additions & 0 deletions examples/rspack/src/Apple.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<template>
<p>{{ t('language') }}</p>
<p>{{ t('hello') }}</p>
</template>

<script>
import { useI18n } from 'vue-i18n'

export default {
name: 'Apple',
setup() {
const { t } = useI18n({
inheritLocale: true,
useScope: 'local'
})
return { t }
}
}
</script>

<i18n>
[
"language",
"hello",
]
</i18n>
29 changes: 29 additions & 0 deletions examples/rspack/src/Banana.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<template>
<form id="fruits">
<label>{{ t('select') }}</label>
<select v-model.number="select">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
</form>
<p>{{ t('fruits.banana', select, { n: select }) }}</p>
</template>

<script>
import { ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'

export default {
name: 'Banana',
setup() {
const { t, locale } = useI18n({ useScope: 'global' })
watch(locale, (val, old) => {
console.log('locale changed', val, old)
})
const select = ref(0)
return { t, select }
}
}
</script>
3 changes: 3 additions & 0 deletions examples/rspack/src/locales/en.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
select: Do you want banana?
fruits:
banana: 'no bananas | {n} banana | {n} bananas'
6 changes: 6 additions & 0 deletions examples/rspack/src/locales/ja.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"select": "バナナが欲しい?",
"fruits": {
"banana": "バナナがない | バナナ {n} 個"
}
}
19 changes: 19 additions & 0 deletions examples/rspack/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { createApp } from 'vue'
import { createI18n } from 'vue-i18n'
import App from './App.vue'

import ja from './locales/ja.json'
import en from './locales/en.yaml'

const i18n = createI18n({
locale: 'ja',
messages: {
en,
ja
}
})

const app = createApp(App)

app.use(i18n)
app.mount('#app')
10 changes: 9 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
"@rollup/plugin-node-resolve": "^13.0.0",
"@rollup/plugin-replace": "^2.4.2",
"@rollup/pluginutils": "^4.1.0",
"@rspack/cli": "^1.2.7",
"@rspack/core": "^1.2.7",
"@types/debug": "^4.1.5",
"@types/eslint": "^9.6.1",
"@types/js-yaml": "^4.0.3",
Expand Down Expand Up @@ -109,8 +111,10 @@
"build:example": "run-s \"build:example:vite {@}\" \"build:example:webpack\" --",
"build:example:vite": "cd examples/vite && vite build --config ./vite.config.ts --outDir ./dist",
"build:example:webpack": "pnpm build && webpack --config ./examples/webpack/webpack.config.js",
"build:example:rspack": "pnpm build && rspack --config ./examples/rspack/rsbuild.config.js",
"play:vite": "vite examples/vite -c examples/vite/vite.config.ts",
"play:webpack": "pnpm run build:unplugin && webpack serve --config ./examples/webpack/webpack.config.js",
"play:rspack": "rspack dev --config ./examples/rspack/rspack.config.js",
"preview:vite": "vite preview examples/vite --outDir dist",
"check-install": "jiti scripts/playwright.ts",
"clean": "run-p \"clean:*\"",
Expand All @@ -133,10 +137,14 @@
"test:e2e:vite": "pnpm --filter @intlify/vite-plugin-vue-i18n test:e2e",
"test:e2e:webpack": "pnpm --filter @intlify/vue-i18n-loader test:e2e",
"test:e2e:unplugin": "pnpm --filter @intlify/unplugin-vue-i18n test:e2e",
"test:unit": "run-s \"test:unit:utils {@}\" \"test:unit:unplugin {@}\" --",
"test:unit": "run-s \"test:unit:utils {@}\" \"test:unit:unplugin\" --",
"test:unit:utils": "vitest run packages/bundle-utils",
"test:unit:rollup": "vitest run packages/rollup-plugin-vue-i18n/test",
"test:unit:unplugin": "vitest run packages/unplugin-vue-i18n/test",
"test:unit:unplugin-all": "run-s \"test:unit:unplugin:*\"",
"test:unit:unplugin:vite": "TEST_FRAMEWORK=vite vitest run packages/unplugin-vue-i18n/test",
"test:unit:unplugin:webpack": "TEST_FRAMEWORK=webpack vitest run packages/unplugin-vue-i18n/test",
"test:unit:unplugin:rspack": "TEST_FRAMEWORK=rspack vitest run packages/unplugin-vue-i18n/test",
"changelog": "jiti ./scripts/changelog.ts",
"changelog:utils": "pnpm --filter @intlify/bundle-utils changelog",
"changelog:rollup": "pnpm --filter @intlify/rollup-plugin-vue-i18n changelog",
Expand Down
22 changes: 21 additions & 1 deletion packages/unplugin-vue-i18n/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,25 @@ module.exports = {

<br></details>

<details>
<summary>Rspack</summary><br>

```ts
const VueI18nPlugin = require('@intlify/unplugin-vue-i18n/rspack')

// rspack.config.js
module.exports = {
/* ... */
plugins: [
VueI18nPlugin({
/* options */
})
]
}
```

<br></details>

<details>
<summary>Nuxt</summary><br>

Expand Down Expand Up @@ -379,7 +398,7 @@ If you are using petite-vue-i18n, you will need to set this value.

Whether locale messages should be compiled by JIT (Just in Time) compilation with vue-i18n's message compiler.

JIT compilation has been supported since vue-i18n v9.3. This means that since v9 was released until now, the message compiler compiles to executable JavaScript code, however it did not work in the CSP environment. Also, since this was an AOT (Ahead of Time) compilation, it was not possible to dynamically retrieve locale messages from the back-end Database and compose locale messages with programatic.
JIT compilation has been supported since vue-i18n v9.3. This means that since v9 was released until now, the message compiler compiles to executable JavaScript code, however it did not work in the CSP environment. Also, since this was an AOT (Ahead of Time) compilation, it was not possible to dynamically retrieve locale messages from the back-end Database and compose locale messages with programmatic.

> [!WARNING]
> Enabling JIT compilation causes the message compiler to generate AST objects for locale messages instead of JavaScript code. If you pre-compile locale messages with a tool such as the [Intlify CLI](https://github.com/intlify/cli) and import them dynamically, you need to rebuild that resource.
Expand Down Expand Up @@ -424,6 +443,7 @@ If do you will use this option, you need to enable `jitCompilation` option.
```
- vite config: `resolve.alias`
- webpack config: `resolve.alias`
- rspack config: `resolve.alias`
```

If `false` is specified, Vue I18n (vue-i18n) package.json `module` field will be used.
Expand Down
8 changes: 6 additions & 2 deletions packages/unplugin-vue-i18n/build.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,22 @@ export default defineBuildConfig({
{
name: 'webpack',
input: 'src/webpack'
},
{
name: 'rspack',
input: 'src/rspack'
}
],
rollup: {
emitCJS: true
},
externals: ['vite', 'webpack'],
externals: ['vite', 'webpack', '@rspack/core'],
hooks: {
'build:done': async () => {
await Promise.all([
rm(resolve(lib, 'types.cjs')),
rm(resolve(lib, 'types.mjs')),
...['vite', 'webpack'].map(async name => {
...['vite', 'webpack', 'rspack'].map(async name => {
for (const ext of ['d.ts', 'd.cts']) {
const path = resolve(lib, `${name}.${ext}`)
const content = await readFile(path, 'utf-8')
Expand Down
11 changes: 8 additions & 3 deletions packages/unplugin-vue-i18n/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@
"pathe": "^1.0.0",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2",
"unplugin": "^1.1.0",
"unplugin": "^2.2.0",
"vue": "^3.4"
},
"devDependencies": {
"unbuild": "^2.0.0",
"@types/node": "^20.14.8"
"@types/node": "^20.14.8",
"unbuild": "^2.0.0"
},
"engines": {
"node": ">= 18"
Expand All @@ -59,6 +59,7 @@
"unplugin",
"transform",
"webpack",
"rspack",
"vite",
"vue",
"vue-i18n"
Expand All @@ -80,6 +81,10 @@
"import": "./lib/webpack.mjs",
"require": "./lib/webpack.cjs"
},
"./rspack": {
"import": "./lib/rspack.mjs",
"require": "./lib/rspack.cjs"
},
"./types": {
"import": {
"types": "./lib/types.d.mts"
Expand Down
1 change: 1 addition & 0 deletions packages/unplugin-vue-i18n/rspack.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './lib/rspack'
Loading