Skip to content

Commit f2d0d7d

Browse files
authored
feat: support safe SSR with translationSignatures option (#217)
* feat: support safe SSR with `translationSignatures` option * fix: typo
1 parent 446c606 commit f2d0d7d

File tree

3 files changed

+182
-52
lines changed

3 files changed

+182
-52
lines changed

src/transform.ts

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,15 @@ import {
66
createCompoundExpression,
77
TO_DISPLAY_STRING
88
} from '@vue/compiler-dom'
9-
import { isNumber, isObject, isString, isSymbol, toDisplayString, hasOwn } from '@intlify/shared'
9+
import {
10+
isNumber,
11+
isObject,
12+
isString,
13+
isSymbol,
14+
toDisplayString,
15+
hasOwn,
16+
isArray
17+
} from '@intlify/shared'
1018
import { evaluateValue, parseVTExpression } from './transpiler'
1119
import { report, ReportCodes } from './report'
1220
import { createContentBuilder } from './builder'
@@ -70,6 +78,16 @@ export interface TransformVTDirectiveOptions<
7078
* @default 'composition'
7179
*/
7280
mode?: I18nMode
81+
/**
82+
* Translation function signatures
83+
*
84+
* @remarks
85+
* You can specify the signature of the translation function attached to the binding context when it is codegen in the Vue Compiler.
86+
* If you have changed the signature to a non `t` signature in the `setup` hook or `<script setup>`, you can safely SSR it.
87+
* If each Vue component has a different signature for the translation function, you can specify several in an array for safe SSR.
88+
* This option value is `undefined` and the signature attached to the binding context is `t`.
89+
*/
90+
translationSignatures?: string | string[]
7391
}
7492

7593
// compatibility for this commit(v3.0.3)
@@ -142,6 +160,13 @@ export function transformVTDirective<
142160
isString(options.mode) && ['composition', 'legacy'].includes(options.mode)
143161
? options.mode
144162
: 'composition'
163+
// prettier-ignore
164+
const translationSignatures = isString(options.translationSignatures)
165+
? [options.translationSignatures]
166+
: isArray(options.translationSignatures)
167+
? options.translationSignatures
168+
: ['t']
169+
translationSignatures.push(`$t`) // fallback to global scope
145170

146171
return (dir, node, context) => {
147172
const { exp, loc } = dir
@@ -211,7 +236,12 @@ export function transformVTDirective<
211236
return { props: [] }
212237
} else {
213238
const translationParams = parseVTExpression(exp.content)
214-
const code = generateTranslationCode(context, mode, translationParams)
239+
const code = generateTranslationCode(
240+
context,
241+
mode,
242+
translationParams,
243+
translationSignatures
244+
)
215245
context.helper(TO_DISPLAY_STRING)
216246
node.children.push({
217247
type: NodeTypes.INTERPOLATION,
@@ -223,7 +253,12 @@ export function transformVTDirective<
223253
}
224254
} else if (isCompoundExpressionNode(exp)) {
225255
const content = exp.children.map(mapNodeContentHandler).join('')
226-
const code = generateTranslationCode(context, mode, parseVTExpression(content))
256+
const code = generateTranslationCode(
257+
context,
258+
mode,
259+
parseVTExpression(content),
260+
translationSignatures
261+
)
227262
context.helper(TO_DISPLAY_STRING)
228263
node.children.push({
229264
type: NodeTypes.INTERPOLATION,
@@ -360,24 +395,38 @@ function makeParams(value: VTDirectiveValue): [string, NamedValue, TranslateOpti
360395
function generateTranslationCode(
361396
context: TransformContext,
362397
mode: I18nMode,
363-
params: TranslationParams
398+
params: TranslationParams,
399+
translationSignatures: string[]
364400
): string {
365401
return mode === 'composition'
366-
? generateComposableCode(context, params)
402+
? generateComposableCode(context, params, translationSignatures)
367403
: generateLegacyCode(context, params)
368404
}
369405

370-
function generateComposableCode(context: TransformContext, params: TranslationParams): string {
406+
function generateTranslationCallableSignatures(
407+
context: TransformContext,
408+
translationSignatures: string[]
409+
): string {
371410
const { prefixIdentifiers, bindingMetadata } = context
372-
const functionName = 't'
373-
const type = hasOwn(bindingMetadata, functionName) && bindingMetadata[functionName]
374-
// prettier-ignore
375-
const prefixContext = prefixIdentifiers
376-
? type && type.startsWith('setup') || type === BindingTypes.LITERAL_CONST
377-
? '$setup.'
378-
: '_ctx.'
379-
: ''
380-
const baseCode = `${prefixContext}${functionName}`
411+
return translationSignatures
412+
.map(signature => {
413+
const type = hasOwn(bindingMetadata, signature) && bindingMetadata[signature]
414+
const bindingContext = prefixIdentifiers
415+
? (type && type.startsWith('setup')) || type === BindingTypes.LITERAL_CONST
416+
? '$setup.'
417+
: '_ctx.'
418+
: ''
419+
return `${bindingContext}${signature}`
420+
})
421+
.join(' || ')
422+
}
423+
424+
function generateComposableCode(
425+
context: TransformContext,
426+
params: TranslationParams,
427+
translationSignatures: string[]
428+
): string {
429+
const baseCode = `(${generateTranslationCallableSignatures(context, translationSignatures)})`
381430

382431
const builder = createContentBuilder()
383432
builder.push(`${baseCode}(`)

0 commit comments

Comments
 (0)