The underlying mechanism of internationalization support
Underlying Mechanism of Internationalization Support
Vue 3's internationalization functionality is implemented through the underlying APIs provided by @vue/runtime-core
, with core logic concentrated in the createI18n
function and accompanying compiler transformations. The internationalization system is designed as a three-layer architecture: message compilation-time processing, runtime resolution, and dynamic update mechanisms.
Compile-Time Message Transformation
During the Single-File Component (SFC) compilation phase, the v-t
directive and $t
calls in templates are specially processed. The compiler converts static messages into internationalizable data structures:
<!-- Original template -->
<p>{{ $t('message.hello') }}</p>
<!-- Compiled code -->
import { createVNode as _createVNode } from "vue"
export function render(_ctx, _cache) {
return _createVNode("p", null, [
_ctx.$t('message.hello')
])
}
The compiler recognizes three message formats:
- Simple strings:
'login.title'
- Parameterized templates:
'welcome {name}'
- Plural forms:
'cart.items | {count} item'
Runtime Message Resolution System
The instance created by createI18n
is injected into the component tree via Vue's provide/inject mechanism:
// Create i18n instance
const i18n = createI18n({
locale: 'zh-CN',
messages: {
'zh-CN': {
button: {
submit: '提交'
}
},
'en-US': {
button: {
submit: 'Submit'
}
}
}
})
// Install plugin
app.use(i18n)
The core of runtime resolution is the __translate
function, which handles the following logic:
- Path resolution: Splits
'button.submit'
into['button', 'submit']
- Locale chain lookup: Attempts to find
zh
whenzh-CN
is not available - Parameter interpolation: Processes placeholders in the form of
{name}
- Plural handling: Processes different quantity forms based on the
|
separator
Dynamic Locale Switching Implementation
Locale switching is driven by the reactivity system, with the locale value implemented as reactive using ref
:
const i18n = {
get locale() {
return _locale.value
},
set locale(newLocale) {
_locale.value = newLocale
}
}
When components obtain the i18n instance via inject
, a dependency relationship is established:
// Component obtaining i18n instance
const i18n = inject('i18n')
// Mechanism to trigger re-rendering
watch(() => i18n.locale, () => {
// Triggers updates for components using $t
})
Plural Rule Processing Engine
Plural handling is based on the Unicode CLDR specification, with built-in plural classification rules for common languages:
// Russian plural rules
function ruPluralRule(choice) {
const rem100 = choice % 100
if (rem100 > 10 && rem100 < 20) return 2
const rem10 = choice % 10
if (rem10 === 1) return 0
if (rem10 >= 2 && rem10 <= 4) return 1
return 2
}
// Message definition
messages: {
ru: {
apple: 'яблоко | яблока | яблок'
}
}
DateTime Localization
Date formatting is deeply integrated via Intl.DateTimeFormat
:
const dateFormats = {
'en-US': {
short: {
year: 'numeric', month: 'short', day: 'numeric'
}
},
'ja-JP': {
short: {
year: 'numeric', month: 'short', day: 'numeric',
era: 'short'
}
}
}
// Usage
$d(new Date(), 'short')
Component-Level Localization Control
Component-level control is achieved via the useI18n
Composition API:
import { useI18n } from 'vue-i18n'
export default {
setup() {
const { t, locale } = useI18n({
inheritLocale: false,
locale: 'ja',
messages: {
ja: { /* Component-specific messages */ }
}
})
return { t, locale }
}
}
Custom Formatter Extension
Custom formatting logic can be extended via the formatters
option:
const i18n = createI18n({
formatters: {
uppercase: (value) => value.toUpperCase(),
price: (value, locale, arg) => {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency: arg
}).format(value)
}
}
})
// Usage in templates
{{ $n(100, 'price', 'USD') }}
Asynchronous Message Loading Strategy
Dynamic message loading is implemented via the loadLocaleMessages
function:
async function loadLocaleMessages(i18n, locale) {
const messages = await import(`./locales/${locale}.json`)
i18n.setLocaleMessage(locale, messages)
return nextTick()
}
// Load when switching locales
watch(locale, (newLocale) => {
loadLocaleMessages(i18n, newLocale)
})
Type Safety Integration
TypeScript type definitions enhance the development experience:
declare module 'vue-i18n' {
interface DefineLocaleMessage {
login: {
title: string
username: string
password: string
}
}
interface DefineDateTimeFormat {
short: DateTimeFormatOptions
}
}
Performance Optimization Measures
- Message caching: Parsed messages are stored in a WeakMap cache
- Lazy evaluation: Only actually used messages are parsed
- Tree-shaking optimization: Unused language packs are excluded by build tools
- Batch updates: Locale switches are processed in batches using
nextTick
const messageCache = new WeakMap()
function getCachedMessage(key, locale) {
if (!messageCache.has(locale)) {
messageCache.set(locale, new Map())
}
const localeCache = messageCache.get(locale)
if (localeCache.has(key)) {
return localeCache.get(key)
}
// ...Parsing logic
localeCache.set(key, parsed)
return parsed
}
Server-Side Rendering Adaptation
Special handling is required for SSR environments:
// Synchronize state during client-side hydration
if (isClient && __SSR__) {
const initialState = window.__INITIAL_STATE__
if (initialState.i18n) {
i18n.locale = initialState.i18n.locale
i18n.fallbackLocale = initialState.i18n.fallbackLocale
}
}
// Server-side collection of used messages
const usedMessages = new Set()
const originalT = i18n.global.t
i18n.global.t = (...args) => {
usedMessages.add(args[0])
return originalT(...args)
}
Debugging Tool Integration
Detailed warning messages are provided in development mode:
function warnMissing(key, locale) {
if (__DEV__) {
console.warn(
`Missing translation for key: "${key}" in locale: "${locale}"`
)
}
}
// Check for undefined message paths
function resolveMessage(key, locale) {
const res = resolveObjectPath(key, messages[locale])
if (res === undefined) {
warnMissing(key, locale)
}
return res
}
Custom Directive Implementation
Underlying logic of the v-t
directive:
const vTDirective = {
mounted(el, binding) {
const i18n = el._i18n = inject('i18n')
el._locale = computed(() => i18n.locale)
updateText(el, binding)
},
updated(el, binding) {
updateText(el, binding)
}
}
function updateText(el, binding) {
const { value, modifiers } = binding
const path = typeof value === 'string' ? value : value.path
const args = typeof value === 'object' ? value.args : {}
el.textContent = el._i18n.t(path, args)
}
Error Handling Mechanism
Multi-layer error recovery strategies are provided:
- Fallback locale chain: zh-CN → zh → en
- Missing key fallback:
button.submit
→submit
- Silent mode: No errors in production
- Error callback: Configurable
missingHandler
const i18n = createI18n({
missing: (locale, key) => {
if (typeof __INTLIFY_WARN__ !== 'undefined' && __INTLIFY_WARN__) {
warn(`Missing ${key} in ${locale}`)
}
return key // Returns the key name as a last resort
}
})
Integration with Vue Router
Route meta information drives locale switching:
router.beforeEach((to) => {
const newLocale = to.meta.locale || 'en'
if (i18n.locale !== newLocale) {
i18n.locale = newLocale
document.documentElement.lang = newLocale
}
})
Browser Language Auto-Detection
Initial language detection using the Navigator API:
function detectBrowserLocale() {
const nav = typeof navigator !== 'undefined' ? navigator : {}
const lang = nav.language || nav.userLanguage || 'en'
return lang.split('-')[0]
}
const i18n = createI18n({
locale: detectBrowserLocale(),
fallbackLocale: 'en'
})
Unit Testing Support
Test utility functions are provided:
import { createTestI18n } from '@vue-i18n/test-utils'
const wrapper = mount(Component, {
global: {
plugins: [createTestI18n({
locale: 'test',
messages: { test: { hello: 'Test Hello' } }
})]
}
})
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:状态管理库的集成方式
下一篇:浏览器开发者工具的安全检测功能