|
| 1 | +import { promises as fs } from 'fs' |
| 2 | +import path from 'path' |
| 3 | +import { isEmptyObject, isString } from '@intlify/shared' |
| 4 | +import { createFilter } from '@rollup/pluginutils' |
| 5 | +import { generateJSON, generateYAML } from '@intlify/cli' |
1 | 6 | import { debug as Debug } from 'debug' |
2 | | -import { transform } from './transform' |
| 7 | +import { parseVueRequest } from './query' |
3 | 8 |
|
4 | | -import type { Plugin } from 'vite' |
| 9 | +import type { Plugin, ResolvedConfig } from 'vite' |
| 10 | +import type { CodeGenOptions, DevEnv } from '@intlify/cli' |
5 | 11 | import type { VitePluginVueI18nOptions } from './options' |
6 | 12 |
|
7 | 13 | const debug = Debug('vite-plugin-vue-i18n') |
8 | 14 |
|
9 | | -export function pluginI18n(options?: VitePluginVueI18nOptions): Plugin { |
| 15 | +export function pluginI18n( |
| 16 | + options: VitePluginVueI18nOptions = { forceStringify: false } |
| 17 | +): Plugin { |
10 | 18 | debug('plugin options:', options) |
11 | 19 |
|
| 20 | + const filter = createFilter(options.include) |
| 21 | + let config: ResolvedConfig | null = null |
| 22 | + |
12 | 23 | return { |
13 | 24 | name: 'vite-plugin-vue-i18n', |
14 | | - ...transform(options) |
| 25 | + |
| 26 | + configResolved(_config: ResolvedConfig) { |
| 27 | + config = _config |
| 28 | + debug('configResolved', config) |
| 29 | + }, |
| 30 | + |
| 31 | + async transform(code: string, id: string) { |
| 32 | + const { filename, query } = parseVueRequest(id) |
| 33 | + debug('transform', id, code, JSON.stringify(query)) |
| 34 | + |
| 35 | + const parseOptions = getOptions( |
| 36 | + filename, |
| 37 | + config != null ? (config.mode as DevEnv) : 'development', |
| 38 | + query as Record<string, unknown>, |
| 39 | + options.forceStringify |
| 40 | + ) as CodeGenOptions |
| 41 | + debug('parseOptions', parseOptions) |
| 42 | + |
| 43 | + let langInfo = 'json' |
| 44 | + if (!query.vue) { |
| 45 | + if (/\.(json5?|ya?ml)$/.test(id) && filter(id)) { |
| 46 | + langInfo = path.parse(filename).ext |
| 47 | + // NOTE: |
| 48 | + // `.json` is handled default in vite, and it's transformed to JS object. |
| 49 | + let _source = code |
| 50 | + if (langInfo === '.json') { |
| 51 | + _source = await getRawJSON(id) |
| 52 | + } |
| 53 | + const generate = /\.?json5?/.test(langInfo) |
| 54 | + ? generateJSON |
| 55 | + : generateYAML |
| 56 | + const { code: generatedCode } = generate(_source, parseOptions) |
| 57 | + debug('generated code', generatedCode) |
| 58 | + // TODO: error handling & sourcempa |
| 59 | + return Promise.resolve(generatedCode) |
| 60 | + } else { |
| 61 | + return Promise.resolve(code) |
| 62 | + } |
| 63 | + } else { |
| 64 | + // for Vue SFC |
| 65 | + if (isCustomBlock(query as Record<string, unknown>)) { |
| 66 | + if ('src' in query) { |
| 67 | + if (isString(query.lang)) { |
| 68 | + langInfo = query.lang === 'i18n' ? 'json' : query.lang |
| 69 | + } |
| 70 | + } else { |
| 71 | + if (isString(query.lang)) { |
| 72 | + langInfo = query.lang |
| 73 | + } |
| 74 | + } |
| 75 | + const generate = /\.?json5?/.test(langInfo) |
| 76 | + ? generateJSON |
| 77 | + : generateYAML |
| 78 | + const { code: generatedCode } = generate(code, parseOptions) |
| 79 | + debug('generated code', generatedCode) |
| 80 | + // TODO: error handling & sourcempa |
| 81 | + return Promise.resolve(generatedCode) |
| 82 | + } else { |
| 83 | + return Promise.resolve(code) |
| 84 | + } |
| 85 | + } |
| 86 | + } |
| 87 | + } |
| 88 | +} |
| 89 | + |
| 90 | +async function getRawJSON(path: string): Promise<string> { |
| 91 | + return fs.readFile(path, { encoding: 'utf-8' }) |
| 92 | +} |
| 93 | + |
| 94 | +function isCustomBlock(query: Record<string, unknown>): boolean { |
| 95 | + // NOTE: should be more improvement. difference query type and blocktype in some environment ... |
| 96 | + return ( |
| 97 | + !isEmptyObject(query) && |
| 98 | + 'vue' in query && |
| 99 | + (query['type'] === 'custom' || |
| 100 | + query['type'] === 'i18n' || |
| 101 | + query['blockType'] === 'i18n') |
| 102 | + ) |
| 103 | +} |
| 104 | + |
| 105 | +function getOptions( |
| 106 | + filename: string, |
| 107 | + mode: DevEnv, |
| 108 | + query: Record<string, unknown>, |
| 109 | + forceStringify = false |
| 110 | +): Record<string, unknown> { |
| 111 | + const baseOptions = { |
| 112 | + filename, |
| 113 | + forceStringify, |
| 114 | + env: mode, |
| 115 | + onWarn: (msg: string): void => { |
| 116 | + console.warn(`[vite-plugin-vue-i18n]: ${filename} ${msg}`) |
| 117 | + }, |
| 118 | + onError: (msg: string): void => { |
| 119 | + console.error(`[vite-plugin-vue-i18n]: ${filename} ${msg}`) |
| 120 | + } |
| 121 | + } |
| 122 | + |
| 123 | + if (isCustomBlock(query)) { |
| 124 | + return Object.assign(baseOptions, { |
| 125 | + type: 'sfc', |
| 126 | + locale: isString(query.locale) ? query.locale : '', |
| 127 | + isGlobal: query.global != null |
| 128 | + }) |
| 129 | + } else { |
| 130 | + return Object.assign(baseOptions, { |
| 131 | + type: 'plain', |
| 132 | + isGlobal: false |
| 133 | + }) |
15 | 134 | } |
16 | 135 | } |
0 commit comments