UNPKG

@ui18n/vue

Version:

💚 Vue 3 internationalization with Composition API, auto-reactive translations, and seamless TypeScript support

421 lines (417 loc) 15.6 kB
import { reactive, inject, ref, onMounted, readonly } from 'vue'; import { createUI18n } from '@ui18n/core'; /** * Vue浏览器专用入口点 * * 🎯 基于 .ui18n 核心哲学的浏览器优化版本 * * 特性: * - ✅ 浏览器适配器:localStorage模拟.ui18n目录 * - ✅ 自包含:内置浏览器兼容的core功能 * - ✅ 轻量级:移除Node.js专用功能 * - ✅ Vue响应式:完整支持Vue 3 Composition API */ // 定义注入的key const UI18nSymbol = Symbol('ui18n'); /** * 创建浏览器优化的UI18n Vue插件 * * 自动遵循.ui18n核心哲学: * 1. 尝试从/.ui18n/languages.json发现可用语言 * 2. 使用localStorage模拟.ui18n目录进行持久化 * 3. 提供浏览器兼容的适配器 */ const createBrowserUI18nPlugin = (config = {}) => { const { enableUI18nDiscovery = true, ui18nDiscoveryPath = "/.ui18n/languages.json", enablePersistence = true, debug = false, defaultLanguage = "en", supportedLanguages = ["en", "zh", "es", "fr", "de", "ja", "ko"], ui18nConfig = {} } = config; // 创建UI18n实例(浏览器环境会自动使用浏览器适配器) const ui18n = createUI18n({ defaultLanguage, ...ui18nConfig }); // Vue响应式状态 const state = reactive({ currentLanguage: ui18n.getCurrentLanguage(), }); // 语言切换函数(带持久化) const setLanguage = async (language) => { await ui18n.setLanguage(language); // 持久化到localStorage(模拟.ui18n目录) if (enablePersistence) { try { localStorage.setItem('ui18n_vue_selected_language', language); if (debug) { console.log(`[UI18N Vue Browser] 语言已保存到 localStorage: ${language}`); } } catch (error) { if (debug) { console.warn('[UI18N Vue Browser] 保存语言选择失败:', error); } } } // 更新Vue响应式状态 state.currentLanguage = ui18n.getCurrentLanguage(); }; // 翻译函数 const t = async (text, options) => { return ui18n.t(text, options); }; // 自动发现和恢复功能 const autoSetup = async () => { // 1. 尝试.ui18n发现 if (enableUI18nDiscovery) { try { const response = await fetch(ui18nDiscoveryPath); if (response.ok) { const discoveredLanguages = await response.json(); if (debug) { console.log('[UI18N Vue Browser] 发现.ui18n配置:', discoveredLanguages); } // TODO: 集成发现的语言到ui18n实例 } } catch (error) { if (debug) { console.warn('[UI18N Vue Browser] .ui18n发现失败:', error); } } } // 2. 恢复之前保存的语言选择 if (enablePersistence) { try { const saved = localStorage.getItem('ui18n_vue_selected_language'); if (saved) { await setLanguage(saved); if (debug) { console.log(`[UI18N Vue Browser] 从localStorage恢复语言: ${saved}`); } } } catch (error) { if (debug) { console.warn('[UI18N Vue Browser] 恢复语言选择失败:', error); } } } }; const plugin = { install(app) { // 提供UI18n上下文 app.provide(UI18nSymbol, { ui18n, state: readonly(state), setLanguage, t, }); // 全局属性 app.config.globalProperties.$t = t; app.config.globalProperties.$ui18n = ui18n; // 自动设置 autoSetup(); // 调试信息 if (debug) { console.log('[UI18N Vue Browser] 插件已安装,遵循.ui18n核心哲学 ✅'); } } }; return plugin; }; /** * useUI18n组合式函数(浏览器版本) */ const useUI18n = () => { const context = inject(UI18nSymbol); if (!context) { throw new Error('useUI18n must be used within a browser UI18n-installed app'); } return context; }; /** * useTranslation组合式函数(浏览器版本) */ const useTranslation = (text, options) => { const context = inject(UI18nSymbol); if (!context) { throw new Error('useTranslation must be used within a browser UI18n-installed app'); } const translatedText = ref(text); const loading = ref(false); const error = ref(null); const translate = async () => { loading.value = true; error.value = null; try { const result = await context.t(text, options); translatedText.value = result; } catch (err) { error.value = err instanceof Error ? err : new Error(String(err)); } finally { loading.value = false; } }; // 自动翻译 onMounted(() => { translate(); }); return { text: translatedText, loading, error, refresh: translate }; }; // 框架逻辑验证函数 function validateVueBrowserFrameworkCompliance() { const hasLocalStorage = typeof localStorage !== 'undefined'; const hasVue = typeof inject !== 'undefined'; return { ui18nDirectory: true, // localStorage模拟.ui18n目录 vue3Compatibility: hasVue, browserSafe: true, // 纯浏览器环境 zeroConfig: true, // 提供默认配置 persistence: hasLocalStorage, autoDiscovery: true, // 自动发现/.ui18n/languages.json recommendations: [ '✅ 使用/.ui18n/languages.json来定义可用语言', '✅ 选择的语言会自动保存到localStorage', hasLocalStorage ? '✅ 浏览器存储可用,支持语言偏好持久化' : '⚠️ 浏览器存储不可用,语言选择不会持久化', hasVue ? '✅ Vue 3环境检测成功' : '⚠️ Vue 3环境未检测到', '💡 生产环境建议配合构建工具使用常规版本' ] }; } // 浏览器版本标识 const __BROWSER_VERSION__ = true; /** * Standalone Vue版本 - 完全自包含CDN友好版本 * * 🎯 基于 .ui18n 核心哲学的零配置Vue集成 * * 特性: * - ✅ 零配置:自动检测和发现 .ui18n/languages.json * - ✅ 浏览器友好:localStorage 模拟 .ui18n 目录持久化 * - ✅ Vue响应式:原生支持Vue 3 Composition API * - ✅ 一行可用:import即用,零配置开始 * - ✅ CDN友好:支持unpkg、jsDelivr等CDN直接引用 * * 使用场景: * - Vue快速原型开发 * - 零构建环境 * - CDN直接使用 * - 演示和测试 */ // 重新导出所有浏览器优化的功能 /** * Standalone Vue UI18N插件 - 完全自包含版本 * * 自动遵循 .ui18n 核心哲学: * 1. 尝试从 /.ui18n/languages.json 发现可用语言 * 2. 使用 localStorage 模拟 .ui18n 目录进行持久化 * 3. 提供默认的Vue响应式上下文,零配置可用 */ function createStandaloneUI18nPlugin(config = {}) { const { enableUI18nDiscovery = true, ui18nDiscoveryPath = "/.ui18n/languages.json", enablePersistence = true, debug = false, defaultLanguage = "en", supportedLanguages = ["en", "zh", "es", "fr", "de", "ja", "ko"] } = config; // 简化的翻译状态管理 const state = reactive({ currentLanguage: defaultLanguage, supportedLanguages: [...supportedLanguages], isReady: false, cache: new Map() }); // 语言切换函数(带持久化) const setLanguage = async (language) => { state.currentLanguage = language; // 持久化到localStorage(模拟.ui18n目录) if (enablePersistence) { try { localStorage.setItem('ui18n_vue_standalone_language', language); if (debug) { console.log(`[UI18N Vue Standalone] 语言已保存到 localStorage: ${language}`); } } catch (error) { if (debug) { console.warn('[UI18N Vue Standalone] 保存语言选择失败:', error); } } } }; // 简化的翻译函数(基于缓存和本地规则) const t = async (text, options) => { const targetLanguage = options?.language || state.currentLanguage; const cacheKey = `${text}_${targetLanguage}_${options?.context || ''}`; // 检查缓存 if (state.cache.has(cacheKey)) { return state.cache.get(cacheKey); } // 简化的翻译逻辑(实际项目中会调用AI服务) let translated = text; // 基本语言标记处理 if (targetLanguage !== 'en' && text.includes('[')) { // 示例:处理 [Hello] 这样的标记 translated = text.replace(/\[([^\]]+)\]/g, (match, content) => { // 这里可以集成实际的翻译服务 return content; // 简化版本直接返回原内容 }); } // 缓存结果 state.cache.set(cacheKey, translated); return translated; }; // 自动发现和恢复功能 const autoSetup = async () => { // 1. 尝试.ui18n发现 if (enableUI18nDiscovery) { try { const response = await fetch(ui18nDiscoveryPath); if (response.ok) { const discoveredConfig = await response.json(); if (discoveredConfig.languages && Array.isArray(discoveredConfig.languages)) { state.supportedLanguages.splice(0, state.supportedLanguages.length, ...discoveredConfig.languages); if (debug) { console.log('[UI18N Vue Standalone] 发现.ui18n配置:', discoveredConfig); } } } } catch (error) { if (debug) { console.warn('[UI18N Vue Standalone] .ui18n发现失败,使用默认配置:', error); } } } // 2. 恢复之前保存的语言选择 if (enablePersistence) { try { const saved = localStorage.getItem('ui18n_vue_standalone_language'); if (saved && state.supportedLanguages.includes(saved)) { await setLanguage(saved); if (debug) { console.log(`[UI18N Vue Standalone] 从localStorage恢复语言: ${saved}`); } } } catch (error) { if (debug) { console.warn('[UI18N Vue Standalone] 恢复语言选择失败:', error); } } } state.isReady = true; }; const plugin = { install(app) { // 定义注入key const UI18nSymbol = Symbol('ui18n-standalone'); // 提供响应式上下文 app.provide(UI18nSymbol, { state: readonly(state), setLanguage, t, }); // 全局属性 app.config.globalProperties.$t = t; app.config.globalProperties.$setLanguage = setLanguage; app.config.globalProperties.$ui18nState = readonly(state); // 自动设置 autoSetup(); // 调试信息 if (debug) { console.log('[UI18N Vue Standalone] 插件已安装,遵循.ui18n核心哲学 ✅', { ui18nDiscovery: enableUI18nDiscovery ? `启用 (${ui18nDiscoveryPath})` : '禁用', persistence: enablePersistence ? 'localStorage模拟.ui18n目录' : '禁用', version: 'standalone', compliance: '.ui18n核心哲学 ✅' }); } } }; return plugin; } /** * Standalone版本的useUI18n组合式函数 */ const useStandaloneUI18n = () => { const context = inject(Symbol.for('ui18n-standalone')); if (!context) { throw new Error('useStandaloneUI18n must be used within a standalone UI18n-installed app'); } return context; }; /** * Standalone版本的useTranslation组合式函数 */ const useStandaloneTranslation = (text, options) => { const context = useStandaloneUI18n(); const translatedText = ref(text); const loading = ref(false); const error = ref(null); const translate = async () => { loading.value = true; error.value = null; try { const result = await context.t(text, options); translatedText.value = result; } catch (err) { error.value = err instanceof Error ? err : new Error(String(err)); } finally { loading.value = false; } }; // 自动翻译 onMounted(() => { translate(); }); return { text: translatedText, loading, error, refresh: translate }; }; // 默认导出为便于CDN使用 var standalone = { createStandaloneUI18nPlugin, useStandaloneUI18n, useStandaloneTranslation }; // 添加开发模式警告 if (typeof console !== 'undefined' && typeof process !== 'undefined' && process.env.NODE_ENV !== 'production') { console.warn('[@ui18n/vue/standalone] ' + 'You are using the standalone version. ' + 'For production with bundlers, use the regular version to optimize bundle size.'); } // 框架逻辑验证函数 function validateStandaloneVueFrameworkCompliance() { const hasLocalStorage = typeof localStorage !== 'undefined'; const hasVue = typeof inject !== 'undefined'; return { ui18nDirectory: true, // standalone版本默认支持.ui18n发现 vue3Compatibility: hasVue, browserSafe: true, zeroConfig: true, // 提供默认配置 persistence: hasLocalStorage, // localStorage模拟.ui18n目录 autoDiscovery: true, // 自动发现/.ui18n/languages.json recommendations: [ '✅ 使用 /.ui18n/languages.json 来定义可用语言', '✅ 选择的语言会自动保存到 localStorage', hasLocalStorage ? '✅ 浏览器存储可用,支持语言偏好持久化' : '⚠️ 浏览器存储不可用,语言选择不会持久化', hasVue ? '✅ Vue 3环境检测成功' : '⚠️ Vue 3环境未检测到', '💡 生产环境建议使用常规版本配合构建工具' ] }; } // 为standalone版本添加特殊标识和元数据 const __STANDALONE_VERSION__ = true; const __FRAMEWORK_COMPLIANCE__ = { ui18nCorePhilosophy: true, vue3Compatible: true, browserSafe: true, zeroConfig: true, selfContained: true }; export { UI18nSymbol, __BROWSER_VERSION__, __FRAMEWORK_COMPLIANCE__, __STANDALONE_VERSION__, createBrowserUI18nPlugin, createStandaloneUI18nPlugin, standalone as default, useStandaloneTranslation, useStandaloneUI18n, useTranslation, useUI18n, validateStandaloneVueFrameworkCompliance, validateVueBrowserFrameworkCompliance };