Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"ts-jest": "^25.3.0",
"typescript": "^3.8.3",
"typescript-eslint-language-service": "^2.0.3",
"vue": "^3.0.0-beta.4"
"vue": "^3.0.0-beta.5"
},
"engines": {
"node": ">= 10"
Expand All @@ -85,7 +85,7 @@
"main": "dist/vue-i18n.cjs.js",
"module": "dist/vue-i18n.esm-bundler.js",
"peerDependencies": {
"vue": "^3.0.0-beta.4"
"vue": "^3.0.0-beta.5"
},
"repository": {
"type": "git",
Expand Down
46 changes: 44 additions & 2 deletions src/composer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
} from 'vue'
import { WritableComputedRef, ComputedRef } from '@vue/reactivity'
import { apply } from './plugin'
import { Path } from './path'
import { Path, parse as parsePath } from './path'
import {
DateTimeFormats,
NumberFormats,
Expand All @@ -27,6 +27,7 @@ import {
LinkedModifiers,
PluralizationRules,
NamedValue,
MessageFunctions,
MessageProcessor
} from './message/runtime'
import {
Expand Down Expand Up @@ -77,7 +78,11 @@ export type MissingHandler = (
type?: string
) => string | void

export type CustomBlocks = string[]
export type PreCompileHandler = () => {
messages: LocaleMessages
functions: MessageFunctions
}
export type CustomBlocks = string[] | PreCompileHandler

/**
* Composer Options
Expand Down Expand Up @@ -189,21 +194,58 @@ function getLocaleMessages(
locale: Locale
): LocaleMessages {
const { messages, __i18n } = options

// prettier-ignore
let ret = isPlainObject(messages)
? messages
: isArray(__i18n)
? {}
: { [locale]: {} }

// merge locale messages of i18n custom block
if (isArray(__i18n)) {
__i18n.forEach(raw => {
ret = Object.assign(ret, JSON.parse(raw))
})
return ret
}

if (isFunction(__i18n)) {
const { functions } = __i18n()
addPreCompileMessages(ret, functions)
}

return ret
}

function addPreCompileMessages(
messages: LocaleMessages,
functions: MessageFunctions
): void {
const keys = Object.keys(functions)
keys.forEach(key => {
const compiled = functions[key]
const { l, k } = JSON.parse(key)
const targetLocaleMessage = (messages[l] = messages[l] || {})
const paths = parsePath(k)
if (paths != null) {
const len = paths.length
let last = targetLocaleMessage as any // eslint-disable-line @typescript-eslint/no-explicit-any
let i = 0
while (i < len) {
const path = paths[i]
const val = last[path]
if (val != null) {
last[path] = {}
}
last = val
i++
}
last = compiled
}
})
}

/**
* Composer
*
Expand Down
2 changes: 1 addition & 1 deletion src/core/context.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MessageFunction } from '../message/compiler'
import { MessageFunction } from '../message/runtime'
import {
LinkedModifiers,
PluralizationRules,
Expand Down
39 changes: 26 additions & 13 deletions src/core/translate.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Path, resolveValue, PathValue } from '../path'
import { CompileOptions } from '../message/options'
import { CompileError } from '../message/errors'
import { compile, MessageFunction } from '../message/compiler'
import { compile } from '../message/compiler'
import {
createMessageContext,
NamedValue,
MessageFunction,
MessageContextOptions
} from '../message/runtime'
import {
Expand All @@ -25,6 +26,7 @@ import {
isArray,
isPlainObject,
isEmptyObject,
generateFormatCacheKey,
generateCodeFrame
} from '../utils'

Expand Down Expand Up @@ -232,23 +234,33 @@ export function translate(
return unresolving ? NOT_REOSLVED : key
}

// compile message format
// setup compile error detecting
let occured = false
const errorDetector = () => {
occured = true
}
const msg = isMessageFunction(format)
? format
: compile(

// compile message format
let msg
if (!isMessageFunction(format)) {
msg = compile(
format,
getCompileOptions(
targetLocale,
cacheBaseKey,
format,
getCompileOptions(
targetLocale,
cacheBaseKey,
format,
warnHtmlMessage,
errorDetector
)
warnHtmlMessage,
errorDetector
)
)
msg.locale = targetLocale
msg.key = key
msg.source = format
} else {
msg = format
msg.locale = msg.locale || targetLocale
msg.key = msg.key || key
}

// if occured compile error, return the message format
if (occured) {
Expand Down Expand Up @@ -326,7 +338,8 @@ function getCompileOptions(
throw err
}
},
onCacheKey: (source: string): string => `{${locale}}{${key}}{${source}}`
onCacheKey: (source: string): string =>
generateFormatCacheKey(locale, key, source)
} as CompileOptions
}

Expand Down
16 changes: 14 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
export { generateFormatCacheKey, friendlyJSONstringify } from './utils'
export { Path, PathValue } from './path'
export { createParser, Parser } from './message/parser'
export { CompileOptions } from './message/options'
export { PluralizationRule, LinkedModifiers } from './message/runtime'
export {
CompileError,
CompileDomain,
CompileErrorCodes
} from './message/errors'
export { CompileOptions, CompileErrorHandler } from './message/options'
export { baseCompile, compile } from './message/compiler'
export {
MessageFunction,
MessageFunctions,
PluralizationRule,
LinkedModifiers
} from './message/runtime'
export {
Locale,
FallbackLocale,
Expand Down
34 changes: 22 additions & 12 deletions src/message/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { createParser, ResourceNode } from './parser'
import { transform } from './transformer'
import { generate } from './generator'
import { CompileError, defaultOnError } from './errors'
import { MessageFunction, MessageFunctions } from './runtime'
import { warn, isBoolean } from '../utils'

export type CompileResult = {
Expand All @@ -17,8 +18,6 @@ export type Compiler = Readonly<{
compile: (source: string, options?: CompileOptions) => CompileResult
}>

export type MessageFunction = (ctx: unknown) => unknown

// TODO: This code should be removed with using rollup (`/*#__PURE__*/`)
const RE_HTML_TAG = /<\/?[\w\s="/.':;#-\/]+>/
function checkHtmlMessage(source: string, options: CompileOptions): void {
Expand All @@ -33,7 +32,24 @@ function checkHtmlMessage(source: string, options: CompileOptions): void {
}

const defaultOnCacheKey = (source: string): string => source
const compileCache: Record<string, MessageFunction> = Object.create(null)
const compileCache: MessageFunctions = Object.create(null)

export function baseCompile(
source: string,
options: CompileOptions = {}
): CompileResult {
// parse source codes
const parser = createParser({ ...options })
const ast = parser.parse(source)

// transform ASTs
transform(ast, { ...options })

// generate javascript codes
const code = generate(ast, { ...options })

return { ast, code }
}

export function compile(
source: string,
Expand All @@ -58,16 +74,10 @@ export function compile(
onError(err)
}

// parse source codes
const parser = createParser({ ...options })
const ast = parser.parse(source)

// transform ASTs
transform(ast, { ...options })

// generate javascript codes
const code = generate(ast, { ...options })
// compile
const { code } = baseCompile(source, options)

// evaluate function
const msg = new Function(`return ${code}`)() as MessageFunction

// if occured compile error, don't cache
Expand Down
11 changes: 8 additions & 3 deletions src/message/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@ export type PluralizationRule = (
export type PluralizationRules = { [locale: string]: PluralizationRule }
export type LinkedModify = (value: unknown, type: string) => unknown
export type LinkedModifiers = { [key: string]: LinkedModify }
export type MessageFunction = (ctx: MessageContext) => unknown
export type MessageFucntions = { [key: string]: MessageFunction }
export type MessageFunction = {
(ctx: MessageContext): unknown
key?: string
locale?: string
source?: string
}
export type MessageFunctions = Record<string, MessageFunction>
export type MessageResolveFunction = (key: string) => MessageFunction
export type NamedValue<T = {}> = T & { [prop: string]: unknown }
export type MessageNormalize = (values: unknown[]) => unknown
Expand All @@ -37,7 +42,7 @@ export type MessageContextOptions<N = {}> = {
modifiers?: LinkedModifiers
pluralIndex?: number
pluralRules?: PluralizationRules
messages?: MessageFucntions | MessageResolveFunction // TODO: need to design resolve message function?
messages?: MessageFunctions | MessageResolveFunction // TODO: need to design resolve message function?
processor?: MessageProcessor
}

Expand Down
12 changes: 12 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@
export const generateSymbolID = (): string =>
`vue-i18n-${new Date().getUTCMilliseconds().toString()}`

export const generateFormatCacheKey = (
locale: string,
key: string,
source: string
): string => friendlyJSONstringify({ l: locale, k: key, s: source })

export const friendlyJSONstringify = (json: unknown): string =>
JSON.stringify(json)
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029')
.replace(/\u0027/g, '\\u0027')

export const isDate = (val: unknown): val is Date =>
toTypeString(val) === '[object Date]'

Expand Down
6 changes: 2 additions & 4 deletions test/message/compiler.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* eslint-disable @typescript-eslint/no-empty-function */
/* eslint-disable @typescript-eslint/no-empty-function, no-irregular-whitespace */

// utils
jest.mock('../../src/utils', () => ({
Expand All @@ -9,12 +9,10 @@ import { warn } from '../../src/utils'

import { compile } from '../../src/message/compiler'

/* eslint-disable no-irregular-whitespace */
test(`@.caml:{'no apples'} | {0} apple | {n} apples`, () => {
const code = compile(`@.caml:{'no apples'} | {0} apple | {n} apples`)
expect(code.toString()).toMatchSnapshot('code')
})
/* eslint-enable no-irregular-whitespace */

describe('warnHtmlMessage', () => {
test('default', () => {
Expand Down Expand Up @@ -50,4 +48,4 @@ describe('edge cases', () => {
})
})

/* eslint-enable @typescript-eslint/no-empty-function */
/* eslint-enable @typescript-eslint/no-empty-function, no-irregular-whitespace */
Loading