@intlify/vue-i18n-extensions-nightly
Version:
vue-i18n extensions
322 lines (321 loc) • 12.4 kB
JavaScript
;
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 */