UNPKG

@intlify/vue-i18n-extensions-nightly

Version:
322 lines (321 loc) 12.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.transformVTDirective = void 0; /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-enum-comparison */ const compiler_dom_1 = require("@vue/compiler-dom"); const shared_1 = require("@intlify/shared"); const transpiler_1 = require("./transpiler"); const report_1 = require("./report"); const builder_1 = require("./builder"); /** * Transform `v-t` custom directive * * @remarks * Transform that `v-t` custom directive is optimized vue-i18n code by Vue compiler. * This transform can improve the performance by pre-translating, and it does support SSR. * * @param options - `v-t` custom directive transform options, see {@link TransformVTDirectiveOptions} * @returns Directive transform * * @example * ```js * import { compile } from '@vue/compiler-dom' * import { createI18n } from 'vue-i18n' * import { transformVTDirective } from '@intlify/vue-i18n-extensions' * * // create i18n instance * const i18n = createI18n({ * locale: 'ja', * messages: { * en: { * hello: 'hello' * }, * ja: { * hello: 'こんにちは' * } * } * }) * * // get transform from `transformVTDirective` function, with `i18n` option * const transformVT = transformVTDirective({ i18n }) * * const { code } = compile(`<p v-t="'hello'"></p>`, { * mode: 'function', * hoistStatic: true, * prefixIdentifiers: true, * directiveTransforms: { t: transformVT } // <- you need to specify to `directiveTransforms` option! * }) * * console.log(code) * // output -> * // const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock } = Vue * // return function render(_ctx, _cache) { * // return (_openBlock(), _createBlock(\\"div\\", null, \\"こんにちは!\\")) * // } * ``` * @public */ function transformVTDirective(options = {}) { const i18nInstance = options.i18n; const mode = (0, shared_1.isString)(options.mode) && ['composition', 'legacy'].includes(options.mode) ? options.mode : 'composition'; return (dir, node, context) => { const { exp, loc } = dir; // console.log('v-t dir', dir) // console.log('v-t node', node) if (!exp) { // TODO: throw error with context.OnError // NOTE: We need to support from @vue/compiler-core // https://github.com/vuejs/vue-next/issues/1147 (0, report_1.report)(1 /* ReportCodes.UNEXPECTED_DIRECTIVE_EXPRESSION */, { mode: 'error', args: [node.loc.source || ''], loc: node.loc }); } if (node.children.length > 0) { // TODO: throw error with context.OnError // NOTE: We need to support from @vue/compiler-core // https://github.com/vuejs/vue-next/issues/1147 (0, report_1.report)(7 /* ReportCodes.OVERRIDE_ELEMENT_CHILDREN */, { mode: 'error', args: [node.loc.source || ''], loc: node.loc }); node.children.length = 0; } if (dir.modifiers.includes('preserve')) { (0, report_1.report)(6 /* ReportCodes.NOT_SUPPORTED_PRESERVE */, { args: [node.loc.source || ''], loc: node.loc }); } if (isSimpleExpressionNode(exp)) { if (isConstant(exp) && i18nInstance) { const { status, value } = (0, transpiler_1.evaluateValue)(exp.content); if (status === 'ng') { (0, report_1.report)(3 /* ReportCodes.FAILED_VALUE_EVALUATION */, { args: [node.loc.source || ''], loc: node.loc }); return { props: [] }; } const [parsedValue, parseStatus] = parseValue(value); if (parseStatus !== 0 /* ReportCodes.SUCCESS */) { (0, report_1.report)(parseStatus, { args: [node.loc.source || ''], loc: node.loc }); return { props: [] }; } const global = i18nInstance.mode === 'composition' ? i18nInstance.global // eslint-disable-line @typescript-eslint/no-explicit-any : i18nInstance.global.__composer; // eslint-disable-line @typescript-eslint/no-explicit-any const content = global.t(...makeParams(parsedValue)); node.children.push({ type: compiler_dom_1.NodeTypes.TEXT, content }); return { props: [] }; } else { const translationParams = (0, transpiler_1.parseVTExpression)(exp.content); const code = generateTranslationCode(context, mode, translationParams); context.helper(compiler_dom_1.TO_DISPLAY_STRING); node.children.push({ type: compiler_dom_1.NodeTypes.INTERPOLATION, content: (0, compiler_dom_1.createCompoundExpression)([ (0, compiler_dom_1.createSimpleExpression)(code, false, loc, // eslint-disable-next-line @typescript-eslint/no-explicit-any 0 /* ConstantTypes.NOT_CONSTANT */) ]) }); return { props: [] }; } } else if (isCompoundExpressionNode(exp)) { const content = exp.children.map(mapNodeContentHandler).join(''); const code = generateTranslationCode(context, mode, (0, transpiler_1.parseVTExpression)(content)); context.helper(compiler_dom_1.TO_DISPLAY_STRING); node.children.push({ type: compiler_dom_1.NodeTypes.INTERPOLATION, content: (0, compiler_dom_1.createCompoundExpression)([ (0, compiler_dom_1.createSimpleExpression)(code, false, loc, // eslint-disable-next-line @typescript-eslint/no-explicit-any 0 /* ConstantTypes.NOT_CONSTANT */) ]) }); return { props: [] }; } else { (0, report_1.report)(2 /* ReportCodes.NOT_SUPPORTED */, { args: [node.loc.source || ''], loc: node.loc }); return { props: [] }; } }; } exports.transformVTDirective = transformVTDirective; function isSimpleExpressionNode(node) { return node != null && node.type === compiler_dom_1.NodeTypes.SIMPLE_EXPRESSION; } function isCompoundExpressionNode(node) { return node != null && node.type === compiler_dom_1.NodeTypes.COMPOUND_EXPRESSION; } function isConstant(node) { if ('isConstant' in node) { // for v3.0.3 earlier // eslint-disable-next-line @typescript-eslint/no-explicit-any return node.isConstant; } else if ('constType' in node) { // for v3.0.3 or later return node.constType <= 3 /* ConstantTypes.CAN_STRINGIFY */; } else { throw Error('unexpected error'); } } function mapNodeContentHandler(value) { if ((0, shared_1.isString)(value)) { return value; } else if ((0, shared_1.isSymbol)(value)) { return value.description || ''; } else if (isSimpleExpressionNode(value)) { return value.content; } else if (isCompoundExpressionNode(value)) { return value.children.map(mapNodeContentHandler).join(''); } else if ((0, compiler_dom_1.isText)(value)) { if ((0, shared_1.isString)(value.content)) { return value.content; } else if (isSimpleExpressionNode(value.content)) { return value.content.content; } else if (isCompoundExpressionNode(value.content)) { return value.content.children.map(mapNodeContentHandler).join(''); } else { return ''; } } else { return ''; } } function parseValue(value) { if ((0, shared_1.isString)(value)) { return [{ path: value }, 0 /* ReportCodes.SUCCESS */]; } else if ((0, shared_1.isObject)(value)) { if (!('path' in value)) { return [null, 4 /* ReportCodes.REQUIRED_PARAMETER */]; } return [value, 0 /* ReportCodes.SUCCESS */]; } else { return [null, 5 /* ReportCodes.INVALID_PARAMETER_TYPE */]; } } function makeParams(value) { const { path, locale, args, choice, plural } = value; // eslint-disable-next-line @typescript-eslint/no-explicit-any const options = {}; const named = args || {}; if ((0, shared_1.isString)(locale)) { options.locale = locale; } if ((0, shared_1.isNumber)(choice)) { options.plural = choice; } if ((0, shared_1.isNumber)(plural)) { options.plural = plural; } return [path, named, options]; } function generateTranslationCode(context, mode, params) { return mode === 'composition' ? generateComposableCode(context, params) : generateLegacyCode(context, params); } function generateComposableCode(context, params) { const baseCode = `${context.prefixIdentifiers ? '_ctx.' : ''}t`; const builder = (0, builder_1.createContentBuilder)(); builder.push(`${baseCode}(`); // generate path builder.push(`${(0, shared_1.toDisplayString)(params.path)}`); // generate named builder.push(`, { `); generateNamedCode(builder, params.named); builder.push(` }`); // generate options builder.push(`, { `); if (params.options.locale) { builder.push(`locale: ${(0, shared_1.toDisplayString)(params.options.locale)}`); } if (params.options.plural) { if (params.options.locale) { builder.push(', '); } builder.push(`plural: ${(0, shared_1.toDisplayString)(params.options.plural)}`); } builder.push(` }`); builder.push(`)`); const content = builder.content; return content; } // eslint-disable-next-line @typescript-eslint/no-explicit-any function generateNamedCode(builder, named) { const keys = Object.keys(named); keys.forEach(k => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const v = named[k]; if ((0, shared_1.isObject)(v)) { builder.push(`${k}: { `); generateNamedCode(builder, v); builder.push(` }`); } else { builder.push(`${k}: ${(0, shared_1.toDisplayString)(v)}`); } }); } function generateLegacyCode(context, params) { const mode = !params.options.plural ? 'basic' : 'plural'; const baseCode = `${context.prefixIdentifiers ? '_ctx.' : ''}${mode === 'basic' ? '$t' : '$tc'}`; const builder = (0, builder_1.createContentBuilder)(); builder.push(`${baseCode}(`); // generate path builder.push(`${(0, shared_1.toDisplayString)(params.path)}`); if (mode === 'basic') { // generate locale if ((0, shared_1.isString)(params.options.locale)) { builder.push(`, ${(0, shared_1.toDisplayString)(params.options.locale)}`); } // generate named builder.push(`, { `); generateNamedCode(builder, params.named); builder.push(` }`); } else { // generate plural builder.push(`, ${(0, shared_1.toDisplayString)(params.options.plural)}`); if ((0, shared_1.isString)(params.options.locale)) { // generate locale builder.push(`, ${(0, shared_1.toDisplayString)(params.options.locale)}`); } else { // generate named builder.push(`, { `); generateNamedCode(builder, params.named); builder.push(` }`); } } builder.push(`)`); const content = builder.content; return content; } /* eslint-enable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-enum-comparison */