diff --git a/.eslintrc.js b/.eslintrc.js
index 3a2d784..9f402e5 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -16,8 +16,8 @@ module.exports = {
'plugin:vue-libs/recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/eslint-recommended',
- 'prettier/@typescript-eslint',
- 'plugin:prettier/recommended'
+ 'plugin:prettier/recommended',
+ 'prettier'
],
plugins: ['@typescript-eslint'],
parser: 'vue-eslint-parser',
@@ -29,6 +29,8 @@ module.exports = {
'object-curly-spacing': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/member-delimiter-style': 'off',
- '@typescript-eslint/no-use-before-define': 'off'
+ '@typescript-eslint/no-use-before-define': 'off',
+ '@typescript-eslint/no-non-null-assertion': 'off',
+ '@typescript-eslint/ban-ts-comment': 'off'
}
}
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index aab0659..2129ee7 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1,7 +1,7 @@
# These are supported funding model platforms
github: kazupon
-patreon: kazupon
+patreon: # kazupon
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index d698fd8..d38c90d 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -11,11 +11,11 @@ jobs:
if: github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'release')
runs-on: Ubuntu-latest
steps:
- - uses: actions/checkout@v1
- - uses: actions/setup-node@v1
+ - uses: actions/checkout@v2
+ - uses: actions/setup-node@v2
with:
registry-url: "https://registry.npmjs.org"
- - run: git switch master
+ - run: git switch next
- run: |
if [ -f "yarn.lock" ]; then
yarn install
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index c8ca522..7e4b6a1 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -14,12 +14,12 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
- node: [10, 12]
+ node: [10, 12, 14]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Node.js ${{ matrix.node }}
- uses: actions/setup-node@v1
+ uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node }}
- name: Install
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 7267a75..6a1aee0 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -5,5 +5,9 @@
],
"eslint.packageManager": "yarn",
"eslint.enable": true,
- "typescript.tsdk": "node_modules/typescript/lib"
+ "typescript.tsdk": "node_modules/typescript/lib",
+ "i18n-ally.localesPaths": [
+ "example/composition/locales",
+ "example/legacy/locales"
+ ]
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d447269..d838931 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,110 @@
+## v2.0.2 (2021-03-01)
+
+#### :bug: Bug Fixes
+* [#168](https://github.com/intlify/vue-i18n-loader/pull/168) fix: export default warning ([@kazupon](https://github.com/kazupon))
+
+#### Committers: 1
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+
+## v2.0.1 (2021-03-01)
+
+#### :zap: Improvement Features
+* [#165](https://github.com/intlify/vue-i18n-loader/pull/165) upgrade deps ([@kazupon](https://github.com/kazupon))
+
+#### Committers: 1
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+## v2.0.0 (2021-03-01)
+
+#### Committers: 1
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+
+## v2.0.0-rc.3 (2021-02-26)
+
+#### :zap: Improvement Features
+* [#161](https://github.com/intlify/vue-i18n-loader/pull/161) improvement: intlify vue plugin ([@kazupon](https://github.com/kazupon))
+
+#### Committers: 1
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+
+## v2.0.0-rc.2 (2021-02-26)
+
+#### :star: Features
+* [#159](https://github.com/intlify/vue-i18n-loader/pull/159) experimental: component options injection plugin ([@kazupon](https://github.com/kazupon))
+
+#### Committers: 1
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+## v2.0.0-rc.1 (2021-02-09)
+
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+## v2.0.0-beta.3 (2020-12-21)
+
+#### :star: Features
+* [#141](https://github.com/intlify/vue-i18n-loader/pull/141) feat: i18n resource fully pre-compilation ([@kazupon](https://github.com/kazupon))
+
+#### :zap: Improvement Features
+* [#146](https://github.com/intlify/vue-i18n-loader/pull/146) imporovement: custom block fully pre-compilation ([@kazupon](https://github.com/kazupon))
+
+#### Committers: 2
+- Yosuke Ota ([@ota-meshi](https://github.com/ota-meshi))
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+
+## v2.0.0-beta.2 (2020-12-04)
+
+#### :star: Features
+* [#138](https://github.com/intlify/vue-i18n-loader/pull/138) feat: global attribute ([@kazupon](https://github.com/kazupon))
+
+#### Committers: 2
+- Ousmane NDIAYE ([@ousmaneNdiaye](https://github.com/ousmaneNdiaye))
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+## v2.0.0-beta.1 (2020-09-14)
+
+Nothing (due to be released vue-i18n-next@v9 beta)
+
+
+## v2.0.0-alpha.3 (2020-06-14)
+
+#### :boom: Breaking Change
+* [#109](https://github.com/intlify/vue-i18n-loader/pull/109) breaking: i18n resource to object from string ([@kazupon](https://github.com/kazupon))
+
+#### Committers: 1
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+
+## v2.0.0-alpha.2 (2020-05-02)
+
+#### :bug: Bug Fixes
+* [#95](https://github.com/intlify/vue-i18n-loader/pull/95) fix: move prettier to deps from devDeps ([@kazupon](https://github.com/kazupon))
+
+#### Committers: 1
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+
+## v2.0.0-alpha.1 (2020-05-02)
+
+#### :star: Features
+* [#93](https://github.com/intlify/vue-i18n-loader/pull/93) feat: i18n custom block pre-compilation bundling ([@kazupon](https://github.com/kazupon))
+
+#### Committers: 1
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+## v2.0.0-alpha.0 (2020-04-08)
+
+### :boom: Breaking changes
+* Support for vue-loader@next
+
+#### Committers: 1
+- kazuya kawaguchi ([@kazupon](https://github.com/kazupon))
+
+
## v1.0.0 (2020-04-07)
#### :pencil: Documentation
@@ -105,6 +211,6 @@
# 0.1.0 (2017-03-29)
-### :hatched_chick:
+### :hatched_chick:
* First Release
diff --git a/README.md b/README.md
index 2b6fc53..e6d4bb9 100644
--- a/README.md
+++ b/README.md
@@ -4,33 +4,149 @@
+
-
vue-i18n loader for custom blocks
+**NOTE:** :warning: This `next` branch is development branch for Vue 3! The version for Vue 2 is now in [`master`](https://github.com/intlify/vue-i18n-loader/tree/master) branch!
+
+
+
+## :star: Features
+- i18n resource pre-compilation
+- i18n custom block
+ - i18n resource definition
+ - i18n resource importing
+ - Locale of i18n resource definition
+ - Locale of i18n resource definition for global scope
+ - i18n resource formatting
+
+
## :cd: Installation
- $ npm i --save-dev @intlify/vue-i18n-loader
+### NPM
+
+```sh
+$ npm i --save-dev @intlify/vue-i18n-loader@next
+```
+
+### YARN
+
+```sh
+$ yarn add -D @intlify/vue-i18n-loader@next
+```
+
+
+## :rocket: i18n resource pre-compilation
+
+### Why do we need to require the configuration?
+
+Since vue-i18n@v9.0, The locale messages are handled with message compiler, which converts them to javascript functions after compiling. After compiling, message compiler converts them into javascript functions, which can improve the performance of the application.
+
+However, with the message compiler, the javascript function conversion will not work in some environments (e.g. CSP). For this reason, vue-i18n@v9.0 and later offer a full version that includes compiler and runtime, and a runtime only version.
+
+If you are using the runtime version, you will need to compile before importing locale messages by managing them in a file such as `.json`.
+
+You can pre-commpile by configuring vue-i18n-loader as the webpack loader.
+
+### webpack configration
+
+As an example, if your project has the locale messagess in `src/locales`, your webpack config will look like this:
+
+```
+├── dist
+├── index.html
+├── package.json
+├── src
+│ ├── App.vue
+│ ├── locales
+│ │ ├── en.json
+│ │ └── ja.json
+│ └── main.js
+└── webpack.config.js
+```
+
+```js
+import { createApp } from 'vue'
+import { createI18n } from 'vue-i18n' // import from runtime only
+import App from './App.vue'
+
+// import i18n resources
+import en from './locale/en.json'
+import ja from './locale/ja.json'
+
+const i18n = createI18n({
+ locale: 'ja',
+ messages: {
+ en,
+ ja
+ }
+})
+
+const app = createApp(App)
+app.use(i18n)
+app.mount('#app')
+```
+
+In the case of the above project, you can use vue-i18n with webpack configuration to the following for runtime only:
+
+```javascript
+module.exports = {
+ module: {
+ rules: [
+ // ...
+ {
+ test: /\.(json5?|ya?ml)$/, // target json, json5, yaml and yml files
+ type: 'javascript/auto',
+ loader: '@intlify/vue-i18n-loader',
+ include: [ // Use `Rule.include` to specify the files of locale messages to be pre-compiled
+ path.resolve(__dirname, 'src/locales')
+ ]
+ },
+ // ...
+ ]
+ }
+}
+```
-## :rocket: Usage
+The above uses webpack's `Rule.include` to specify the i18n resources to be precompiled. You can also use [`Rule.exclude`](https://webpack.js.org/configuration/module/#ruleexclude) to set the target.
-the below example that`App.vue` have `i18n` custom block:
-### Basic
+## :rocket: i18n custom block
+
+The below example that `App.vue` have i18n custom block:
+
+### i18n resource definition
```vue
- {{ $t('hello') }}
+ {{ t('hello') }}
@@ -46,18 +162,18 @@ export default {
```
-The locale messages defined at `i18n` custom blocks are **json format default**.
+The locale messages defined at i18n custom blocks are **json format default**.
-### Source importing
+### i18n resource importing
-you also can:
+You also can use `src` attribute:
```vue
```
```json5
-// ./myLnag.json
+// ./myLang.json
{
"en": {
"hello": "hello world!"
@@ -68,9 +184,9 @@ you also can:
}
```
-### Locale definition
+### Locale of i18n resource definition
-You can define locale messages for each locale with `locale` attr in single-file components:
+You can define locale messages for each locale with `locale` attribute in single-file components:
```vue
@@ -88,8 +204,21 @@ You can define locale messages for each locale with `locale` attr in single-file
The above defines two locales, which are merged at target single-file components.
+### Locale of i18n resource definition for global scope
-### Locale Messages formatting
+You can define locale messages for global scope with `global` attribute:
+
+```vue
+
+{
+ "en": {
+ "hello": "hello world!"
+ }
+}
+
+```
+
+### i18n resource formatting
Besides json format, You can be used by specifying the following format in the `lang` attribute:
@@ -124,14 +253,13 @@ example json5 format:
### JavaScript
```javascript
-import Vue from 'vue'
-import VueI18n from 'vue-i18n'
+import { createApp } from 'vue'
+import { createI18n } from 'vue-i18n'
import App from './App.vue'
-Vue.use(VueI18n)
-
-const i18n = new VueI18n({
- locale: 'en',
+// setup i18n instance with globaly
+const i18n = createI18n({
+ locale: 'ja',
messages: {
en: {
// ...
@@ -141,65 +269,90 @@ const i18n = new VueI18n({
}
}
})
-new Vue({
- i18n,
- render: h => h(App)
-}).$mount('#app')
-```
-
-### Webpack Config
-`vue-loader` (v15 or later):
+const app = createApp(App)
-```javascript
-// for vue.config.js (Vue CLI)
-module.exports = {
- chainWebpack: config => {
- config.module
- .rule('i18n')
- .resourceQuery(/blockType=i18n/)
- .type('javascript/auto')
- .use('i18n')
- .loader('@intlify/vue-i18n-loader')
- }
-}
+app.use(i18n)
+app.mount('#app')
```
-`vue-loader` (v15 or later):
+### webpack Config
+
+`vue-loader` (`next` version):
```javascript
-// for webpack.config.js (Without Vue CLI)
module.exports = {
module: {
rules: [
+ // ...
{
resourceQuery: /blockType=i18n/,
type: 'javascript/auto',
- loader: '@intlify/vue-i18n-loader',
+ loader: '@intlify/vue-i18n-loader'
},
+ // ...
]
}
}
```
-`vue-loader` (~v14.x):
-```javascript
-// for webpack config file
-module.exports = {
- module: {
- rules: [{
- test: /\.vue$/,
- loader: 'vue',
- options: {
- loaders: {
- i18n: '@intlify/vue-i18n-loader'
- }
- }
- }]
+## :wrench: Options
+
+### `forceStringify`
+
+- **Type:** `boolean`
+- **Default:** `false`
+
+ Whether pre-compile number and boolean values as message functions that return the string value.
+
+ for example, the following json resources:
+
+ ```json
+ {
+ "trueValue": true,
+ "falseValue": false,
+ "nullValue": null,
+ "numberValue": 1
}
-}
-```
+ ```
+
+ after pre-compiled (development):
+
+ ```js
+ export default {
+ "trueValue": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize(["true"])};fn.source="true";return fn;})(),
+ "falseValue": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize(["false"])};fn.source="false";return fn;})(),
+ "nullValue": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize(["null"])};fn.source="null";return fn;})(),
+ "numberValue": (()=>{const fn=(ctx) => {const { normalize: _normalize } = ctx;return _normalize(["1"])};fn.source="1";return fn;})()
+ }
+ ```
+
+ webpack configration:
+
+ ```javascript
+ module.exports = {
+ module: {
+ rules: [
+ // ...
+ {
+ test: /\.(json5?|ya?ml)$/,
+ type: 'javascript/auto',
+ include: [path.resolve(__dirname, './src/locales')],
+ use: [
+ {
+ loader: '@intlify/vue-i18n-loader',
+ options: {
+ forceStringify: true
+ }
+ }
+ ]
+ },
+ // ...
+ ]
+ }
+ }
+ ```
## :scroll: Changelog
Details changes for each release are documented in the [CHANGELOG.md](https://github.com/intlify/vue-i18n-loader/blob/master/CHANGELOG.md).
diff --git a/e2e/composition.test.js b/e2e/composition.test.js
new file mode 100644
index 0000000..37cd6fa
--- /dev/null
+++ b/e2e/composition.test.js
@@ -0,0 +1,23 @@
+describe('composition', () => {
+ beforeAll(async () => {
+ await page.goto(`http://localhost:8080/composition/`)
+ })
+
+ test('initial rendering', async () => {
+ await expect(page).toMatch('言語')
+ await expect(page).toMatch('こんにちは、世界!')
+ await expect(page).toMatch('バナナが欲しい?')
+ await expect(page).toMatch('バナナ 0 個')
+ })
+
+ test('change locale', async () => {
+ await page.select('#app select', 'en')
+ await expect(page).toMatch('Language')
+ await expect(page).toMatch('hello, world!')
+ })
+
+ test('change banana select', async () => {
+ await page.select('#fruits select', '3')
+ await expect(page).toMatch('バナナ 3 個')
+ })
+})
diff --git a/e2e/example.test.js b/e2e/example.test.js
deleted file mode 100644
index 0d0d65f..0000000
--- a/e2e/example.test.js
+++ /dev/null
@@ -1,9 +0,0 @@
-describe('example', () => {
- beforeAll(async () => {
- await page.goto('http://localhost:8080/')
- })
-
- test('rendering', async () => {
- await expect(page).toMatch('こんにちは、世界!')
- })
-})
diff --git a/e2e/global.test.js b/e2e/global.test.js
new file mode 100644
index 0000000..188e3fa
--- /dev/null
+++ b/e2e/global.test.js
@@ -0,0 +1,16 @@
+describe(`global`, () => {
+ beforeAll(async () => {
+ await page.goto(`http://localhost:8080/global/`)
+ })
+
+ test('initial rendering', async () => {
+ await expect(page).toMatch('言語')
+ await expect(page).toMatch('こんにちは、世界!')
+ })
+
+ test('change locale', async () => {
+ await page.select('#app select', 'en')
+ await expect(page).toMatch('Language')
+ await expect(page).toMatch('hello, world!')
+ })
+})
diff --git a/e2e/legacy.test.js b/e2e/legacy.test.js
new file mode 100644
index 0000000..8cfe1f8
--- /dev/null
+++ b/e2e/legacy.test.js
@@ -0,0 +1,26 @@
+describe('legacy', () => {
+ beforeAll(async () => {
+ await page.goto(`http://localhost:8080/legacy/`)
+ })
+
+ test('initial rendering', async () => {
+ await expect(page).toMatch('言語')
+ await expect(page).toMatch('こんにちは、世界!')
+ await expect(page).toMatch('バナナが欲しい?')
+ await expect(page).toMatch('バナナ 0 個')
+ })
+
+ test('change locale', async () => {
+ await page.select('#app select', 'en')
+ await expect(page).toMatch('Language')
+ await expect(page).toMatch('hello, world!')
+ await expect(page).toMatch('no bananas')
+ })
+
+ test('change banana select', async () => {
+ await page.select('#fruits select', '3')
+ await expect(page).toMatch('3 bananas')
+ await page.select('#app select', 'ja')
+ await expect(page).toMatch('バナナ 3 個')
+ })
+})
diff --git a/example/App.vue b/example/App.vue
deleted file mode 100644
index 7f10c85..0000000
--- a/example/App.vue
+++ /dev/null
@@ -1,20 +0,0 @@
-
- {{ $t('hello') }}
-
-
-
-
-
-{
- "en": {
- "hello": "hello, world!"
- },
- "ja": {
- "hello": "こんにちは、世界!"
- }
-}
-
diff --git a/example/composition/App.vue b/example/composition/App.vue
new file mode 100644
index 0000000..140944a
--- /dev/null
+++ b/example/composition/App.vue
@@ -0,0 +1,43 @@
+
+
+ {{ t('hello') }}
+
+
+
+
+
+
+{
+ "en": {
+ "language": "Language",
+ "hello": "hello, world!"
+ },
+ "ja": {
+ "language": "言語",
+ "hello": "こんにちは、世界!"
+ }
+}
+
diff --git a/example/composition/Banana.vue b/example/composition/Banana.vue
new file mode 100644
index 0000000..84b0853
--- /dev/null
+++ b/example/composition/Banana.vue
@@ -0,0 +1,26 @@
+
+
+ {{ t('fruits.banana', select, { n: select }) }}
+
+
+
diff --git a/example/composition/index.html b/example/composition/index.html
new file mode 100644
index 0000000..fd99226
--- /dev/null
+++ b/example/composition/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ vue-i18n-loader example
+
+
+
+
+
+
diff --git a/example/composition/locales/en.yaml b/example/composition/locales/en.yaml
new file mode 100644
index 0000000..85d055d
--- /dev/null
+++ b/example/composition/locales/en.yaml
@@ -0,0 +1,3 @@
+select: Do you want banana?
+fruits:
+ banana: 'no bananas | {n} banana | {n} bananas'
diff --git a/example/composition/locales/ja.json b/example/composition/locales/ja.json
new file mode 100644
index 0000000..df96dc6
--- /dev/null
+++ b/example/composition/locales/ja.json
@@ -0,0 +1,6 @@
+{
+ "select": "バナナが欲しい?",
+ "fruits": {
+ "banana": "バナナがない | バナナ {n} 個"
+ }
+}
diff --git a/example/composition/main.js b/example/composition/main.js
new file mode 100644
index 0000000..f7028a7
--- /dev/null
+++ b/example/composition/main.js
@@ -0,0 +1,20 @@
+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({
+ legacy: false,
+ locale: 'ja',
+ messages: {
+ en,
+ ja
+ }
+})
+
+const app = createApp(App)
+
+app.use(i18n)
+app.mount('#app')
diff --git a/example/global/App.vue b/example/global/App.vue
new file mode 100644
index 0000000..d71d86e
--- /dev/null
+++ b/example/global/App.vue
@@ -0,0 +1,41 @@
+
+
+ {{ t('hello') }}
+
+
+
+
+
+{
+ "en": {
+ "language": "Language",
+ "hello": "hello, world!"
+ },
+ "ja": {
+ "language": "言語",
+ "hello": "こんにちは、世界!"
+ }
+}
+
diff --git a/example/global/index.html b/example/global/index.html
new file mode 100644
index 0000000..2bd91cc
--- /dev/null
+++ b/example/global/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ vue-i18n-loader global example
+
+
+
+
+
+
diff --git a/example/global/main.js b/example/global/main.js
new file mode 100644
index 0000000..da0524c
--- /dev/null
+++ b/example/global/main.js
@@ -0,0 +1,18 @@
+import { createApp } from 'vue'
+import { createI18n } from 'vue-i18n'
+import App from './App.vue'
+
+const i18n = createI18n({
+ legacy: false,
+ locale: 'ja',
+ messages: {
+ en: {
+ foo: 'foo'
+ }
+ }
+})
+
+const app = createApp(App)
+
+app.use(i18n)
+app.mount('#app')
diff --git a/example/legacy/App.vue b/example/legacy/App.vue
new file mode 100644
index 0000000..6f523ad
--- /dev/null
+++ b/example/legacy/App.vue
@@ -0,0 +1,35 @@
+
+
+ {{ $t('hello') }}
+
+
+
+
+
+
+{
+ "en": {
+ "language": "Language",
+ "hello": "hello, world!"
+ },
+ "ja": {
+ "language": "言語",
+ "hello": "こんにちは、世界!"
+ }
+}
+
diff --git a/example/legacy/Banana.vue b/example/legacy/Banana.vue
new file mode 100644
index 0000000..289946a
--- /dev/null
+++ b/example/legacy/Banana.vue
@@ -0,0 +1,19 @@
+
+
+ {{ $tc('fruits.banana', select, { n: select }) }}
+
+
+
diff --git a/example/index.html b/example/legacy/index.html
similarity index 61%
rename from example/index.html
rename to example/legacy/index.html
index 7abd5dd..ffd9fc7 100644
--- a/example/index.html
+++ b/example/legacy/index.html
@@ -5,7 +5,9 @@
vue-i18n-loader example
-
-
+
+