Unplugin that provides comprehensive Vue I18n integration capabilities for various bundlers including Vite, Webpack, and Nuxt
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Pre-compilation and transformation of i18n resource files including JSON, YAML, JavaScript, and TypeScript locale files. Handles static bundling and virtual module generation.
Access to pre-compiled locale messages through virtual imports.
/**
* Virtual module providing all compiled locale messages
* Automatically merges all included locale resources by locale key
*/
declare module '@intlify/unplugin-vue-i18n/messages' {
import type { I18nOptions } from 'vue-i18n';
const messages: I18nOptions['messages'];
export default messages;
}Usage Example:
import { createI18n } from 'vue-i18n';
import messages from '@intlify/unplugin-vue-i18n/messages';
const i18n = createI18n({
locale: 'en',
messages // Pre-compiled and merged messages
});Individual locale file imports with pre-compilation.
/**
* Import individual locale files
* Files are pre-compiled based on their format
*/
declare module '*.json' {
const messages: Record<string, any>;
export default messages;
}
declare module '*.yaml' {
const messages: Record<string, any>;
export default messages;
}
declare module '*.yml' {
const messages: Record<string, any>;
export default messages;
}
declare module '*.json5' {
const messages: Record<string, any>;
export default messages;
}Usage Example:
// Individual imports
import en from './locales/en.json';
import fr from './locales/fr.yaml';
import de from './locales/de.json5';
const i18n = createI18n({
locale: 'en',
messages: { en, fr, de }
});The plugin supports multiple locale resource formats with automatic format detection.
/**
* Supported locale resource formats
*/
type SupportedFormats =
| 'json' // Standard JSON format
| 'json5' // JSON5 with comments and trailing commas
| 'yaml' // YAML format
| 'yml' // YAML format (alternative extension)
| 'js' // JavaScript modules with export default
| 'ts'; // TypeScript modules with export defaultConfigure how resources are processed and included.
interface ResourceProcessingOptions {
/**
* Pattern(s) to include i18n resource files
* Supports glob patterns and arrays
*/
include?: string | string[];
/**
* Specific locales to include in bundle
* Other locales will be excluded
*/
onlyLocales?: string | string[];
/**
* Allow dynamic resource construction for JS/TS files
* Enables programmatic message loading
* @default false
*/
allowDynamic?: boolean;
/**
* Force stringify non-string values (numbers, booleans, null)
* Converts them to message functions returning strings
* @default false
*/
forceStringify?: boolean;
}Handle JavaScript and TypeScript locale files with both static and dynamic patterns.
/**
* Static export pattern for JS/TS resources
*/
interface StaticJSResource {
// Simple default export of locale object
export default {
hello: 'Hello, {name}!',
welcome: 'Welcome to our app'
};
}
/**
* Dynamic resource construction for JS/TS files
* Requires allowDynamic: true
*/
interface DynamicJSResource {
// Export function for dynamic resource construction
export default async function loadResource(url?: string): Promise<Record<string, any>>;
}Static JS/TS Example:
// locales/en.js
export default {
greeting: 'Hello, {name}!',
navigation: {
home: 'Home',
about: 'About',
contact: 'Contact'
},
validation: {
required: 'This field is required',
email: 'Please enter a valid email'
}
};Dynamic JS/TS Example:
// locales/dynamic.js
import baseMessages from './base.json';
export default async function loadResource(url) {
// Fetch additional resources from backend
const dynamicMessages = await fetch('/api/messages').then(r => r.json());
// Merge with base messages
return {
...baseMessages,
...dynamicMessages
};
}YAML files with support for nested structures and multi-document files.
YAML Example:
# locales/en.yaml
greeting: Hello, {name}!
navigation:
home: Home
about: About
contact: Contact
validation:
required: This field is required
email: Please enter a valid email
minLength: Must be at least {min} charactersYAML Limitations:
/**
* YAML processing limitations
*/
interface YAMLLimitations {
// Not supported:
multiDocument: false; // Files with multiple documents (---)
aliases: false; // Aliases with & and *
customTags: false; // Custom tags with !
complexKeys: false; // Non-string keys
// Supported:
nestedObjects: true; // Nested object structures
arrays: true; // Array values
stringInterpolation: true; // String values with placeholders
}Transform locale messages into optimized JavaScript functions at build time.
/**
* Pre-compilation transforms messages into executable functions
*/
interface PreCompiledMessage {
// Original: "Hello, {name}!"
// Compiled to:
(ctx: MessageContext): string;
source: string; // Original message string
}
interface MessageContext {
normalize: (values: any[]) => string;
interpolate: (values: any[]) => string;
// Additional context methods
}Pre-compilation Example:
// Original JSON
{
"greeting": "Hello, {name}!",
"count": "You have {count} message | You have {count} messages"
}
// Pre-compiled output (development)
{
greeting: (() => {
const fn = (ctx) => {
const { normalize: _normalize, interpolate: _interpolate } = ctx;
return _interpolate([
_normalize(['Hello, ']),
_interpolate([_normalize(['name'])]),
_normalize(['!'])
]);
};
fn.source = 'Hello, {name}!';
return fn;
})(),
count: (() => {
const fn = (ctx) => {
const { normalize: _normalize, plural: _plural } = ctx;
return _plural([
_normalize(['You have ', ['count'], ' message']),
_normalize(['You have ', ['count'], ' messages'])
]);
};
fn.source = 'You have {count} message | You have {count} messages';
return fn;
})()
}How multiple resource files are merged when using the virtual module.
/**
* Resource merging strategy for virtual module
*/
interface ResourceMerging {
/**
* Files are grouped by locale identifier
* Locale is determined by filename or directory structure
*/
localeResolution: 'filename' | 'directory';
/**
* Merge strategy for conflicting keys
*/
conflictResolution: 'last-wins' | 'deep-merge';
/**
* Example file structure:
* - locales/en.json -> locale: 'en'
* - locales/en/common.json -> locale: 'en'
* - locales/fr/errors.yaml -> locale: 'fr'
*/
}File Structure Examples:
// Flat structure
// locales/en.json
// locales/fr.yaml
// locales/de.json5
// Results in: { en: {...}, fr: {...}, de: {...} }
// Nested structure
// locales/en/common.json
// locales/en/errors.json
// locales/fr/common.yaml
// Results in: { en: { ...common, ...errors }, fr: { ...common } }
// Mixed structure
// locales/base.json (no locale, skipped)
// locales/en-US.json -> locale: 'en-US'
// locales/zh-CN/app.yaml -> locale: 'zh-CN'Basic Resource Processing:
VueI18nPlugin({
include: [
path.resolve(__dirname, './src/locales/**'),
]
});Advanced Resource Processing:
VueI18nPlugin({
include: [
'./locales/**/*.{json,yaml,yml,json5}',
'./src/components/**/*.json',
'./modules/**/i18n/*.js'
],
onlyLocales: ['en', 'fr', 'de', 'es'],
allowDynamic: true,
forceStringify: true
});Dynamic Resource Loading:
VueI18nPlugin({
include: ['./locales/**/*.js'],
allowDynamic: true
});
// In locale file
export default async function(url) {
const base = await import('./base.json');
const dynamic = await fetch('/api/locale-data').then(r => r.json());
return { ...base.default, ...dynamic };
}