Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(unplugin-vue-i18n): support dynamic resource construction for js / ts formats #241

Merged
merged 2 commits into from Mar 13, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 28 additions & 2 deletions packages/unplugin-vue-i18n/README.md
Expand Up @@ -277,14 +277,16 @@ This plugin will automatically select and bundle `petite-vue-i18n` build accordi
- ts
```

If nothing is specified for this option, i.e. `undefined`, nothing is done to the resource in the above format.

> ⚠️ NOTE:
`json` resources matches this option, it will be handled **before the internal json plugin of bundler, and will not be processed afterwards**, else the option doesn't match, the bundler side will handle.

> ⚠️ NOTE:
`yaml` resources don't support multi documentation with `|`, alias with `&` and `*`, tags with `! `, `@`, etc. Only simple data structures.

> ⚠️ 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.
`js` and `ts` resources are set **simple export (`export default`) as locale messages object, as default**.

```js
export default {
Expand All @@ -293,7 +295,31 @@ This plugin will automatically select and bundle `petite-vue-i18n` build accordi
}
```

If nothing is specified for this option, i.e. `undefined`, nothing is done to the resource in the above format.
If you need to use programmatically dynamic resource construction, you would be enable `allowDynamic` option. about details, see the section.

> ⚠️ 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.

### `allowDynamic`

- **Type:** `boolean`
- **Default:** `false`

Whether or not programmatically dynamic resource construction for `js` or `ts` resource format.

In this case, you need to export the function with `export default` and construct the resource with the function:

```js
import resources from './locales/all.json'

export default async function loadResource(url) {
const res = await import(url).then(r => r.default || r)
return { ...resources, ...res }
}
```

If you fetch some resources from the backend, the data **must be pre-compiled** for production. exmaple is [here](https://github.com/intlify/vue-i18n-next/tree/master/examples/backend).


### `runtimeOnly`

Expand Down
2 changes: 1 addition & 1 deletion packages/unplugin-vue-i18n/package.json
Expand Up @@ -26,7 +26,7 @@
}
},
"dependencies": {
"@intlify/bundle-utils": "^5.0.0",
"@intlify/bundle-utils": "^5.1.2",
"@intlify/shared": "next",
"@rollup/pluginutils": "^5.0.2",
"@vue/compiler-sfc": "^3.2.47",
Expand Down
16 changes: 9 additions & 7 deletions packages/unplugin-vue-i18n/src/index.ts
Expand Up @@ -27,12 +27,7 @@ import { parseVueRequest, VueQuery } from './query'
import { createBridgeCodeGenerator } from './legacy'
import { getRaw, warn, error, raiseError } from './utils'

import type {
UnpluginContextMeta,
UnpluginOptions,
SourceMapCompact
} from 'unplugin'
import type { SourceMapInput } from 'rollup'
import type { UnpluginContextMeta, UnpluginOptions } from 'unplugin'
import type { PluginOptions } from './types'
import type { CodeGenOptions, DevEnv } from '@intlify/bundle-utils'

Expand Down Expand Up @@ -125,6 +120,8 @@ export const unplugin = createUnplugin<PluginOptions>((options = {}, meta) => {
const esm = isBoolean(options.esm) ? options.esm : true
debug('esm', esm)

const allowDynamic = !!options.allowDynamic

let isProduction = false
let sourceMap = false

Expand Down Expand Up @@ -296,6 +293,7 @@ export const unplugin = createUnplugin<PluginOptions>((options = {}, meta) => {
inSourceMap,
isGlobal: globalSFCScope,
useClassComponent,
allowDynamic,
bridge,
exportESM: esm,
forceStringify
Expand Down Expand Up @@ -501,6 +499,7 @@ export const unplugin = createUnplugin<PluginOptions>((options = {}, meta) => {
inSourceMap,
isGlobal: globalSFCScope,
useClassComponent,
allowDynamic,
bridge,
exportESM: esm,
forceStringify
Expand Down Expand Up @@ -743,14 +742,16 @@ function getOptions(
isGlobal = false,
bridge = false,
exportESM = true,
useClassComponent = false
useClassComponent = false,
allowDynamic = false
}: {
inSourceMap?: RawSourceMap
forceStringify?: boolean
isGlobal?: boolean
bridge?: boolean
exportESM?: boolean
useClassComponent?: boolean
allowDynamic?: boolean
}
): Record<string, unknown> {
const mode: DevEnv = isProduction ? 'production' : 'development'
Expand All @@ -761,6 +762,7 @@ function getOptions(
inSourceMap,
forceStringify,
useClassComponent,
allowDynamic,
bridge,
exportESM,
env: mode,
Expand Down
1 change: 1 addition & 0 deletions packages/unplugin-vue-i18n/src/types.ts
@@ -1,6 +1,7 @@
export type SFCLangFormat = 'json' | 'json5' | 'yml' | 'yaml'
export interface PluginOptions {
include?: string | string[]
allowDynamic?: boolean
runtimeOnly?: boolean
compositionOnly?: boolean
fullInstall?: boolean
Expand Down
1 change: 1 addition & 0 deletions packages/unplugin-vue-i18n/test/utils.ts
Expand Up @@ -153,6 +153,7 @@ export async function bundleAndRun(
options.sourcemap = isBoolean(options.sourcemap) || false
options.useClassComponent = isBoolean(options.useClassComponent) || false
options.bridge = isBoolean(options.bridge) || false
options.allowDynamic = isBoolean(options.allowDynamic) || false

const { code, map } = await bundler(fixture, options)

Expand Down
@@ -1,5 +1,6 @@
import { resolve } from 'pathe'
import { bundleVite, bundleAndRun } from '../utils'
import { isFunction } from '@intlify/shared'
import { createMessageContext } from '@intlify/core-base'

const options = {
Expand Down Expand Up @@ -48,3 +49,11 @@ test('ts resource', async () => {
// expect(fn.source).toEqual(`@.caml:{'no apples'} | {0} apple | {n} apples`)
expect(fn(createMessageContext({ named: { n: 3 } }))).toEqual(`3 apples`)
})

test('dynamical resource with js / ts', async () => {
const { module } = await bundleAndRun('ka-JP.ts', bundleVite, {
allowDynamic: true,
...options
})
expect(isFunction(module)).toBe(true)
})
4 changes: 2 additions & 2 deletions yarn.lock
Expand Up @@ -969,7 +969,7 @@ __metadata:
languageName: unknown
linkType: soft

"@intlify/bundle-utils@^5.0.0, @intlify/bundle-utils@workspace:packages/bundle-utils":
"@intlify/bundle-utils@^5.1.2, @intlify/bundle-utils@workspace:packages/bundle-utils":
version: 0.0.0-use.local
resolution: "@intlify/bundle-utils@workspace:packages/bundle-utils"
dependencies:
Expand Down Expand Up @@ -1094,7 +1094,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@intlify/unplugin-vue-i18n@workspace:packages/unplugin-vue-i18n"
dependencies:
"@intlify/bundle-utils": ^5.0.0
"@intlify/bundle-utils": ^5.1.2
"@intlify/shared": next
"@rollup/pluginutils": ^5.0.2
"@vue/compiler-sfc": ^3.2.47
Expand Down