From 12c02b936c1764839c2f643084f8fbfffd9e7b9d Mon Sep 17 00:00:00 2001 From: fxy060608 Date: Thu, 2 Sep 2021 16:13:43 +0800 Subject: [PATCH] feat(vue3): add getLocale,setLocale,onLocaleChange --- packages/uni-i18n/dist/uni-i18n.cjs.js | 261 +++++++++++++----- packages/uni-i18n/dist/uni-i18n.d.ts | 60 +++- .../dist/{uni-i18n.esm.js => uni-i18n.es.js} | 224 +++++++++++---- packages/uni-i18n/package.json | 6 +- packages/uni-mp-alipay/dist/uni.api.esm.js | 45 ++- packages/uni-mp-alipay/dist/uni.mp.esm.js | 14 +- packages/uni-mp-baidu/dist/uni.api.esm.js | 29 +- packages/uni-mp-baidu/dist/uni.mp.esm.js | 76 ++++- packages/uni-mp-kuaishou/dist/uni.api.esm.js | 29 +- packages/uni-mp-kuaishou/dist/uni.mp.esm.js | 14 +- packages/uni-mp-qq/dist/uni.api.esm.js | 29 +- packages/uni-mp-qq/dist/uni.mp.esm.js | 14 +- packages/uni-mp-toutiao/dist/uni.api.esm.js | 29 +- packages/uni-mp-toutiao/dist/uni.mp.esm.js | 14 +- packages/uni-mp-weixin/dist/uni.api.esm.js | 29 +- packages/uni-mp-weixin/dist/uni.mp.esm.js | 14 +- .../uni-quickapp-webview/dist/uni.api.esm.js | 29 +- .../uni-quickapp-webview/dist/uni.mp.esm.js | 14 +- 18 files changed, 782 insertions(+), 148 deletions(-) rename packages/uni-i18n/dist/{uni-i18n.esm.js => uni-i18n.es.js} (53%) diff --git a/packages/uni-i18n/dist/uni-i18n.cjs.js b/packages/uni-i18n/dist/uni-i18n.cjs.js index d2fd405df..5e7e69eff 100644 --- a/packages/uni-i18n/dist/uni-i18n.cjs.js +++ b/packages/uni-i18n/dist/uni-i18n.cjs.js @@ -1,19 +1,21 @@ -'use strict'; - -Object.defineProperty(exports, '__esModule', { value: true }); - +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +const isArray = Array.isArray; const isObject = (val) => val !== null && typeof val === 'object'; +const defaultDelimiters = ['{', '}']; class BaseFormatter { constructor() { this._caches = Object.create(null); } - interpolate(message, values) { + interpolate(message, values, delimiters = defaultDelimiters) { if (!values) { return [message]; } let tokens = this._caches[message]; if (!tokens) { - tokens = parse(message); + tokens = parse(message, delimiters); this._caches[message] = tokens; } return compile(tokens, values); @@ -21,24 +23,24 @@ class BaseFormatter { } const RE_TOKEN_LIST_VALUE = /^(?:\d)+/; const RE_TOKEN_NAMED_VALUE = /^(?:\w)+/; -function parse(format) { +function parse(format, [startDelimiter, endDelimiter]) { const tokens = []; let position = 0; let text = ''; while (position < format.length) { let char = format[position++]; - if (char === '{') { + if (char === startDelimiter) { if (text) { tokens.push({ type: 'text', value: text }); } text = ''; let sub = ''; char = format[position++]; - while (char !== undefined && char !== '}') { + while (char !== undefined && char !== endDelimiter) { sub += char; char = format[position++]; } - const isClosed = char === '}'; + const isClosed = char === endDelimiter; const type = RE_TOKEN_LIST_VALUE.test(sub) ? 'list' : isClosed && RE_TOKEN_NAMED_VALUE.test(sub) @@ -46,12 +48,12 @@ function parse(format) { : 'unknown'; tokens.push({ value: sub, type }); } - else if (char === '%') { - // when found rails i18n syntax, skip text capture - if (format[position] !== '{') { - text += char; - } - } + // else if (char === '%') { + // // when found rails i18n syntax, skip text capture + // if (format[position] !== '{') { + // text += char + // } + // } else { text += char; } @@ -62,7 +64,7 @@ function parse(format) { function compile(tokens, values) { const compiled = []; let index = 0; - const mode = Array.isArray(values) + const mode = isArray(values) ? 'list' : isObject(values) ? 'named' @@ -98,8 +100,8 @@ function compile(tokens, values) { index++; } return compiled; -} - +} + const LOCALE_ZH_HANS = 'zh-Hans'; const LOCALE_ZH_HANT = 'zh-Hant'; const LOCALE_EN = 'en'; @@ -119,7 +121,7 @@ function normalizeLocale(locale, messages) { return; } locale = locale.trim().replace(/_/g, '-'); - if (messages[locale]) { + if (messages && messages[locale]) { return locale; } locale = locale.toLowerCase(); @@ -152,7 +154,7 @@ class I18n { } this.formater = formater || defaultFormatter; this.messages = messages || {}; - this.setLocale(locale); + this.setLocale(locale || LOCALE_EN); if (watcher) { this.watchLocale(watcher); } @@ -165,9 +167,12 @@ class I18n { this.messages[this.locale] = {}; } this.message = this.messages[this.locale]; - this.watchers.forEach((watcher) => { - watcher(this.locale, oldLocale); - }); + // 仅发生变化时,通知 + if (oldLocale !== this.locale) { + this.watchers.forEach((watcher) => { + watcher(this.locale, oldLocale); + }); + } } getLocale() { return this.locale; @@ -178,14 +183,27 @@ class I18n { this.watchers.splice(index, 1); }; } - add(locale, message) { - if (this.messages[locale]) { - Object.assign(this.messages[locale], message); + add(locale, message, override = true) { + const curMessages = this.messages[locale]; + if (curMessages) { + if (override) { + Object.assign(curMessages, message); + } + else { + Object.keys(message).forEach((key) => { + if (!hasOwn(curMessages, key)) { + curMessages[key] = message[key]; + } + }); + } } else { this.messages[locale] = message; } } + f(message, values, delimiters) { + return this.formater.interpolate(message, values, delimiters).join(''); + } t(key, locale, values) { let message = this.message; if (typeof locale === 'string') { @@ -201,39 +219,34 @@ class I18n { } return this.formater.interpolate(message[key], values).join(''); } -} - +} + const ignoreVueI18n = true; -function initLocaleWatcher(appVm, i18n) { - if (appVm.$i18n) { - const vm = appVm.$i18n.vm ? appVm.$i18n.vm : appVm; - vm.$watch(appVm.$i18n.vm ? 'locale' : () => appVm.$i18n.locale, (newLocale) => { - i18n.setLocale(newLocale); - }, { - immediate: true, - }); - } +function watchAppLocale(appVm, i18n) { + appVm.$watch(() => appVm.$locale, (newLocale) => { + i18n.setLocale(newLocale); + }); } -// function getDefaultLocale() { -// if (typeof navigator !== 'undefined') { -// return (navigator as any).userLanguage || navigator.language -// } -// if (typeof plus !== 'undefined') { -// // TODO 待调整为最新的获取语言代码 -// return plus.os.language -// } -// return uni.getSystemInfoSync().language -// } -function initVueI18n(locale = LOCALE_EN, messages = {}, fallbackLocale = LOCALE_EN, watcher) { +function initVueI18n(locale, messages = {}, fallbackLocale, watcher) { // 兼容旧版本入参 if (typeof locale !== 'string') { - [locale, messages] = [messages, locale]; + [locale, messages] = [ + messages, + locale, + ]; } if (typeof locale !== 'string') { - locale = fallbackLocale; + locale = + (typeof uni !== 'undefined' && uni.getLocale && uni.getLocale()) || + LOCALE_EN; + } + if (typeof fallbackLocale !== 'string') { + fallbackLocale = + (typeof __uniConfig !== 'undefined' && __uniConfig.fallbackLocale) || + LOCALE_EN; } const i18n = new I18n({ - locale: locale || fallbackLocale, + locale, fallbackLocale, messages, watcher, @@ -248,17 +261,19 @@ function initVueI18n(locale = LOCALE_EN, messages = {}, fallbackLocale = LOCALE_ } else { const appVm = getApp().$vm; + watchAppLocale(appVm, i18n); if (!appVm.$t || !appVm.$i18n || ignoreVueI18n) { // if (!locale) { // i18n.setLocale(getDefaultLocale()) // } /* eslint-disable no-func-assign */ t = function (key, values) { + // 触发响应式 + appVm.$locale; return i18n.t(key, values); }; } else { - initLocaleWatcher(appVm, i18n); /* eslint-disable no-func-assign */ t = function (key, values) { const $i18n = appVm.$i18n; @@ -277,11 +292,17 @@ function initVueI18n(locale = LOCALE_EN, messages = {}, fallbackLocale = LOCALE_ }; return { i18n, + f(message, values, delimiters) { + return i18n.f(message, values, delimiters); + }, t(key, values) { return t(key, values); }, - add(locale, message) { - return i18n.add(locale, message); + add(locale, message, override = true) { + return i18n.add(locale, message, override); + }, + watch(fn) { + return i18n.watchLocale(fn); }, getLocale() { return i18n.getLocale(); @@ -290,12 +311,126 @@ function initVueI18n(locale = LOCALE_EN, messages = {}, fallbackLocale = LOCALE_ return i18n.setLocale(newLocale); }, }; +} + +const isString = (val) => typeof val === 'string'; +let formater; +function hasI18nJson(jsonObj, delimiters) { + if (!formater) { + formater = new BaseFormatter(); + } + return walkJsonObj(jsonObj, (jsonObj, key) => { + const value = jsonObj[key]; + if (isString(value)) { + if (isI18nStr(value, delimiters)) { + return true; + } + } + else { + return hasI18nJson(value, delimiters); + } + }); } - -exports.I18n = I18n; -exports.LOCALE_EN = LOCALE_EN; -exports.LOCALE_ES = LOCALE_ES; -exports.LOCALE_FR = LOCALE_FR; -exports.LOCALE_ZH_HANS = LOCALE_ZH_HANS; -exports.LOCALE_ZH_HANT = LOCALE_ZH_HANT; -exports.initVueI18n = initVueI18n; +function parseI18nJson(jsonObj, values, delimiters) { + if (!formater) { + formater = new BaseFormatter(); + } + walkJsonObj(jsonObj, (jsonObj, key) => { + const value = jsonObj[key]; + if (isString(value)) { + if (isI18nStr(value, delimiters)) { + jsonObj[key] = compileStr(value, values, delimiters); + } + } + else { + parseI18nJson(value, values, delimiters); + } + }); + return jsonObj; +} +function compileI18nJsonStr(jsonStr, { locale, locales, delimiters, }) { + if (!isI18nStr(jsonStr, delimiters)) { + return jsonStr; + } + if (!formater) { + formater = new BaseFormatter(); + } + const localeValues = []; + Object.keys(locales).forEach((name) => { + if (name !== locale) { + localeValues.push({ + locale: name, + values: locales[name], + }); + } + }); + localeValues.unshift({ locale, values: locales[locale] }); + try { + return JSON.stringify(compileJsonObj(JSON.parse(jsonStr), localeValues, delimiters), null, 2); + } + catch (e) { } + return jsonStr; +} +function isI18nStr(value, delimiters) { + return value.indexOf(delimiters[0]) > -1; +} +function compileStr(value, values, delimiters) { + return formater.interpolate(value, values, delimiters).join(''); +} +function compileValue(jsonObj, key, localeValues, delimiters) { + const value = jsonObj[key]; + if (isString(value)) { + // 存在国际化 + if (isI18nStr(value, delimiters)) { + jsonObj[key] = compileStr(value, localeValues[0].values, delimiters); + if (localeValues.length > 1) { + // 格式化国际化语言 + const valueLocales = (jsonObj[key + 'Locales'] = {}); + localeValues.forEach((localValue) => { + valueLocales[localValue.locale] = compileStr(value, localValue.values, delimiters); + }); + } + } + } + else { + compileJsonObj(value, localeValues, delimiters); + } +} +function compileJsonObj(jsonObj, localeValues, delimiters) { + walkJsonObj(jsonObj, (jsonObj, key) => { + compileValue(jsonObj, key, localeValues, delimiters); + }); + return jsonObj; +} +function walkJsonObj(jsonObj, walk) { + if (isArray(jsonObj)) { + for (let i = 0; i < jsonObj.length; i++) { + if (walk(jsonObj, i)) { + return true; + } + } + } + else if (isObject(jsonObj)) { + for (const key in jsonObj) { + if (walk(jsonObj, key)) { + return true; + } + } + } + return false; +} + +exports.Formatter = BaseFormatter; +exports.I18n = I18n; +exports.LOCALE_EN = LOCALE_EN; +exports.LOCALE_ES = LOCALE_ES; +exports.LOCALE_FR = LOCALE_FR; +exports.LOCALE_ZH_HANS = LOCALE_ZH_HANS; +exports.LOCALE_ZH_HANT = LOCALE_ZH_HANT; +exports.compileI18nJsonStr = compileI18nJsonStr; +exports.hasI18nJson = hasI18nJson; +exports.initVueI18n = initVueI18n; +exports.isI18nStr = isI18nStr; +exports.isString = isString; +exports.normalizeLocale = normalizeLocale; +exports.parseI18nJson = parseI18nJson; diff --git a/packages/uni-i18n/dist/uni-i18n.d.ts b/packages/uni-i18n/dist/uni-i18n.d.ts index b2152ac27..85c675ab6 100644 --- a/packages/uni-i18n/dist/uni-i18n.d.ts +++ b/packages/uni-i18n/dist/uni-i18n.d.ts @@ -1,9 +1,25 @@ export declare type BuiltInLocale = typeof LOCALE_ZH_HANS | typeof LOCALE_ZH_HANT | typeof LOCALE_EN | typeof LOCALE_FR | typeof LOCALE_ES; -export declare interface Formatter { - interpolate: (message: string, values?: Record | Array) => Array; +export declare function compileI18nJsonStr(jsonStr: string, { locale, locales, delimiters, }: { + locale: string; + locales: Record>; + delimiters: [string, string]; +}): string; + +export declare class Formatter { + _caches: { + [key: string]: Array; + }; + constructor(); + interpolate(message: string, values?: Record | Array, delimiters?: [string, string]): Array; +} + +declare interface Formatter_2 { + interpolate: (message: string, values?: Record | Array, delimiters?: [string, string]) => Array; } +export declare function hasI18nJson(jsonObj: unknown, delimiters: [string, string]): boolean; + export declare class I18n { private locale; private fallbackLocale; @@ -13,29 +29,36 @@ export declare class I18n { private formater; constructor({ locale, fallbackLocale, messages, watcher, formater, }: I18nOptions); setLocale(locale: string): void; - getLocale(): BuiltInLocale; + getLocale(): string; watchLocale(fn: LocaleWatcher): () => void; - add(locale: BuiltInLocale, message: Record): void; + add(locale: BuiltInLocale, message: Record, override?: boolean): void; + f(message: string, values?: Record | Array, delimiters?: [string, string]): string; t(key: string, values?: Record | Array | BuiltInLocale): string; t(key: string, locale?: BuiltInLocale, values?: Record | Array): string; } export declare interface I18nOptions { - locale: BuiltInLocale; - fallbackLocale?: BuiltInLocale; + locale: string; + fallbackLocale?: string; messages?: LocaleMessages; - formater?: Formatter; + formater?: Formatter_2; watcher?: LocaleWatcher; } -export declare function initVueI18n(locale?: BuiltInLocale, messages?: LocaleMessages, fallbackLocale?: BuiltInLocale, watcher?: (locale: BuiltInLocale) => void): { +export declare function initVueI18n(locale?: string, messages?: LocaleMessages, fallbackLocale?: string, watcher?: (locale: string) => void): { i18n: I18n; + f(message: string, values?: Record | unknown[] | undefined, delimiters?: [string, string] | undefined): string; t(key: string, values?: Record | unknown[] | undefined): string; - add(locale: BuiltInLocale, message: Record): void; - getLocale(): BuiltInLocale; - setLocale(newLocale: BuiltInLocale): void; + add(locale: BuiltInLocale, message: Record, override?: boolean): void; + watch(fn: LocaleWatcher): () => void; + getLocale(): string; + setLocale(newLocale: string): void; }; +export declare function isI18nStr(value: string, delimiters: [string, string]): boolean; + +export declare const isString: (val: unknown) => val is string; + export declare const LOCALE_EN = "en"; export declare const LOCALE_ES = "es"; @@ -46,10 +69,17 @@ export declare const LOCALE_ZH_HANS = "zh-Hans"; export declare const LOCALE_ZH_HANT = "zh-Hant"; -export declare type LocaleMessages = { - [name in BuiltInLocale]?: Record; -}; +export declare type LocaleMessages = Record>; + +export declare type LocaleWatcher = (newLocale: string, oldLocale: string) => void; + +export declare function normalizeLocale(locale: string, messages?: LocaleMessages): BuiltInLocale | undefined; -export declare type LocaleWatcher = (newLocale: BuiltInLocale, oldLocale: BuiltInLocale) => void; +export declare function parseI18nJson(jsonObj: unknown, values: Record, delimiters: [string, string]): unknown; + +declare type Token = { + type: 'text' | 'named' | 'list' | 'unknown'; + value: string; +}; export { } diff --git a/packages/uni-i18n/dist/uni-i18n.esm.js b/packages/uni-i18n/dist/uni-i18n.es.js similarity index 53% rename from packages/uni-i18n/dist/uni-i18n.esm.js rename to packages/uni-i18n/dist/uni-i18n.es.js index 36c2d5a96..d4d1d6331 100644 --- a/packages/uni-i18n/dist/uni-i18n.esm.js +++ b/packages/uni-i18n/dist/uni-i18n.es.js @@ -1,15 +1,17 @@ +const isArray = Array.isArray; const isObject = (val) => val !== null && typeof val === 'object'; +const defaultDelimiters = ['{', '}']; class BaseFormatter { constructor() { this._caches = Object.create(null); } - interpolate(message, values) { + interpolate(message, values, delimiters = defaultDelimiters) { if (!values) { return [message]; } let tokens = this._caches[message]; if (!tokens) { - tokens = parse(message); + tokens = parse(message, delimiters); this._caches[message] = tokens; } return compile(tokens, values); @@ -17,24 +19,24 @@ class BaseFormatter { } const RE_TOKEN_LIST_VALUE = /^(?:\d)+/; const RE_TOKEN_NAMED_VALUE = /^(?:\w)+/; -function parse(format) { +function parse(format, [startDelimiter, endDelimiter]) { const tokens = []; let position = 0; let text = ''; while (position < format.length) { let char = format[position++]; - if (char === '{') { + if (char === startDelimiter) { if (text) { tokens.push({ type: 'text', value: text }); } text = ''; let sub = ''; char = format[position++]; - while (char !== undefined && char !== '}') { + while (char !== undefined && char !== endDelimiter) { sub += char; char = format[position++]; } - const isClosed = char === '}'; + const isClosed = char === endDelimiter; const type = RE_TOKEN_LIST_VALUE.test(sub) ? 'list' : isClosed && RE_TOKEN_NAMED_VALUE.test(sub) @@ -42,12 +44,12 @@ function parse(format) { : 'unknown'; tokens.push({ value: sub, type }); } - else if (char === '%') { - // when found rails i18n syntax, skip text capture - if (format[position] !== '{') { - text += char; - } - } + // else if (char === '%') { + // // when found rails i18n syntax, skip text capture + // if (format[position] !== '{') { + // text += char + // } + // } else { text += char; } @@ -58,7 +60,7 @@ function parse(format) { function compile(tokens, values) { const compiled = []; let index = 0; - const mode = Array.isArray(values) + const mode = isArray(values) ? 'list' : isObject(values) ? 'named' @@ -115,7 +117,7 @@ function normalizeLocale(locale, messages) { return; } locale = locale.trim().replace(/_/g, '-'); - if (messages[locale]) { + if (messages && messages[locale]) { return locale; } locale = locale.toLowerCase(); @@ -148,7 +150,7 @@ class I18n { } this.formater = formater || defaultFormatter; this.messages = messages || {}; - this.setLocale(locale); + this.setLocale(locale || LOCALE_EN); if (watcher) { this.watchLocale(watcher); } @@ -161,9 +163,12 @@ class I18n { this.messages[this.locale] = {}; } this.message = this.messages[this.locale]; - this.watchers.forEach((watcher) => { - watcher(this.locale, oldLocale); - }); + // 仅发生变化时,通知 + if (oldLocale !== this.locale) { + this.watchers.forEach((watcher) => { + watcher(this.locale, oldLocale); + }); + } } getLocale() { return this.locale; @@ -174,14 +179,27 @@ class I18n { this.watchers.splice(index, 1); }; } - add(locale, message) { - if (this.messages[locale]) { - Object.assign(this.messages[locale], message); + add(locale, message, override = true) { + const curMessages = this.messages[locale]; + if (curMessages) { + if (override) { + Object.assign(curMessages, message); + } + else { + Object.keys(message).forEach((key) => { + if (!hasOwn(curMessages, key)) { + curMessages[key] = message[key]; + } + }); + } } else { this.messages[locale] = message; } } + f(message, values, delimiters) { + return this.formater.interpolate(message, values, delimiters).join(''); + } t(key, locale, values) { let message = this.message; if (typeof locale === 'string') { @@ -200,36 +218,31 @@ class I18n { } const ignoreVueI18n = true; -function initLocaleWatcher(appVm, i18n) { - if (appVm.$i18n) { - const vm = appVm.$i18n.vm ? appVm.$i18n.vm : appVm; - vm.$watch(appVm.$i18n.vm ? 'locale' : () => appVm.$i18n.locale, (newLocale) => { - i18n.setLocale(newLocale); - }, { - immediate: true, - }); - } +function watchAppLocale(appVm, i18n) { + appVm.$watch(() => appVm.$locale, (newLocale) => { + i18n.setLocale(newLocale); + }); } -// function getDefaultLocale() { -// if (typeof navigator !== 'undefined') { -// return (navigator as any).userLanguage || navigator.language -// } -// if (typeof plus !== 'undefined') { -// // TODO 待调整为最新的获取语言代码 -// return plus.os.language -// } -// return uni.getSystemInfoSync().language -// } -function initVueI18n(locale = LOCALE_EN, messages = {}, fallbackLocale = LOCALE_EN, watcher) { +function initVueI18n(locale, messages = {}, fallbackLocale, watcher) { // 兼容旧版本入参 if (typeof locale !== 'string') { - [locale, messages] = [messages, locale]; + [locale, messages] = [ + messages, + locale, + ]; } if (typeof locale !== 'string') { - locale = fallbackLocale; + locale = + (typeof uni !== 'undefined' && uni.getLocale && uni.getLocale()) || + LOCALE_EN; + } + if (typeof fallbackLocale !== 'string') { + fallbackLocale = + (typeof __uniConfig !== 'undefined' && __uniConfig.fallbackLocale) || + LOCALE_EN; } const i18n = new I18n({ - locale: locale || fallbackLocale, + locale, fallbackLocale, messages, watcher, @@ -244,17 +257,19 @@ function initVueI18n(locale = LOCALE_EN, messages = {}, fallbackLocale = LOCALE_ } else { const appVm = getApp().$vm; + watchAppLocale(appVm, i18n); if (!appVm.$t || !appVm.$i18n || ignoreVueI18n) { // if (!locale) { // i18n.setLocale(getDefaultLocale()) // } /* eslint-disable no-func-assign */ t = function (key, values) { + // 触发响应式 + appVm.$locale; return i18n.t(key, values); }; } else { - initLocaleWatcher(appVm, i18n); /* eslint-disable no-func-assign */ t = function (key, values) { const $i18n = appVm.$i18n; @@ -273,11 +288,17 @@ function initVueI18n(locale = LOCALE_EN, messages = {}, fallbackLocale = LOCALE_ }; return { i18n, + f(message, values, delimiters) { + return i18n.f(message, values, delimiters); + }, t(key, values) { return t(key, values); }, - add(locale, message) { - return i18n.add(locale, message); + add(locale, message, override = true) { + return i18n.add(locale, message, override); + }, + watch(fn) { + return i18n.watchLocale(fn); }, getLocale() { return i18n.getLocale(); @@ -288,4 +309,111 @@ function initVueI18n(locale = LOCALE_EN, messages = {}, fallbackLocale = LOCALE_ }; } -export { I18n, LOCALE_EN, LOCALE_ES, LOCALE_FR, LOCALE_ZH_HANS, LOCALE_ZH_HANT, initVueI18n }; +const isString = (val) => typeof val === 'string'; +let formater; +function hasI18nJson(jsonObj, delimiters) { + if (!formater) { + formater = new BaseFormatter(); + } + return walkJsonObj(jsonObj, (jsonObj, key) => { + const value = jsonObj[key]; + if (isString(value)) { + if (isI18nStr(value, delimiters)) { + return true; + } + } + else { + return hasI18nJson(value, delimiters); + } + }); +} +function parseI18nJson(jsonObj, values, delimiters) { + if (!formater) { + formater = new BaseFormatter(); + } + walkJsonObj(jsonObj, (jsonObj, key) => { + const value = jsonObj[key]; + if (isString(value)) { + if (isI18nStr(value, delimiters)) { + jsonObj[key] = compileStr(value, values, delimiters); + } + } + else { + parseI18nJson(value, values, delimiters); + } + }); + return jsonObj; +} +function compileI18nJsonStr(jsonStr, { locale, locales, delimiters, }) { + if (!isI18nStr(jsonStr, delimiters)) { + return jsonStr; + } + if (!formater) { + formater = new BaseFormatter(); + } + const localeValues = []; + Object.keys(locales).forEach((name) => { + if (name !== locale) { + localeValues.push({ + locale: name, + values: locales[name], + }); + } + }); + localeValues.unshift({ locale, values: locales[locale] }); + try { + return JSON.stringify(compileJsonObj(JSON.parse(jsonStr), localeValues, delimiters), null, 2); + } + catch (e) { } + return jsonStr; +} +function isI18nStr(value, delimiters) { + return value.indexOf(delimiters[0]) > -1; +} +function compileStr(value, values, delimiters) { + return formater.interpolate(value, values, delimiters).join(''); +} +function compileValue(jsonObj, key, localeValues, delimiters) { + const value = jsonObj[key]; + if (isString(value)) { + // 存在国际化 + if (isI18nStr(value, delimiters)) { + jsonObj[key] = compileStr(value, localeValues[0].values, delimiters); + if (localeValues.length > 1) { + // 格式化国际化语言 + const valueLocales = (jsonObj[key + 'Locales'] = {}); + localeValues.forEach((localValue) => { + valueLocales[localValue.locale] = compileStr(value, localValue.values, delimiters); + }); + } + } + } + else { + compileJsonObj(value, localeValues, delimiters); + } +} +function compileJsonObj(jsonObj, localeValues, delimiters) { + walkJsonObj(jsonObj, (jsonObj, key) => { + compileValue(jsonObj, key, localeValues, delimiters); + }); + return jsonObj; +} +function walkJsonObj(jsonObj, walk) { + if (isArray(jsonObj)) { + for (let i = 0; i < jsonObj.length; i++) { + if (walk(jsonObj, i)) { + return true; + } + } + } + else if (isObject(jsonObj)) { + for (const key in jsonObj) { + if (walk(jsonObj, key)) { + return true; + } + } + } + return false; +} + +export { BaseFormatter as Formatter, I18n, LOCALE_EN, LOCALE_ES, LOCALE_FR, LOCALE_ZH_HANS, LOCALE_ZH_HANT, compileI18nJsonStr, hasI18nJson, initVueI18n, isI18nStr, isString, normalizeLocale, parseI18nJson }; diff --git a/packages/uni-i18n/package.json b/packages/uni-i18n/package.json index 3e3dac291..706c87650 100644 --- a/packages/uni-i18n/package.json +++ b/packages/uni-i18n/package.json @@ -2,9 +2,9 @@ "name": "@dcloudio/uni-i18n", "version": "2.0.0-31920210709003", "description": "@dcloudio/uni-i18n", - "main": "dist/uni-i18n.cjs.js", - "module": "dist/uni-i18n.esm.js", - "types": "dist/uni-i18n.d.ts", + "main": "./dist/uni-i18n.cjs.js", + "module": "./dist/uni-i18n.es.js", + "types": "./dist/uni-i18n.d.ts", "files": [ "dist" ], diff --git a/packages/uni-mp-alipay/dist/uni.api.esm.js b/packages/uni-mp-alipay/dist/uni.api.esm.js index cbee7b1c7..b319981ff 100644 --- a/packages/uni-mp-alipay/dist/uni.api.esm.js +++ b/packages/uni-mp-alipay/dist/uni.api.esm.js @@ -583,7 +583,7 @@ const $emit = defineSyncApi(API_EMIT, (name, ...args) => { emitter.emit(name, ...args); }, EmitProtocol); -const SYNC_API_RE = /^\$|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; +const SYNC_API_RE = /^\$|getLocale|setLocale|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; const CONTEXT_API_RE = /^create|Manager$/; // Context例外情况 const CONTEXT_API_RE_EXC = ['createBLEConnection']; @@ -727,6 +727,30 @@ function initWrapper(protocols) { }; } +const getLocale = () => { + // 优先使用 $locale + const app = getApp({ allowDefault: true }); + if (app && app.$vm) { + return app.$vm.$locale; + } + return uni.getSystemInfoSync().language || 'zh-Hans'; +}; +const setLocale = (locale) => { + const oldLocale = getApp().$vm.$locale; + if (oldLocale !== locale) { + getApp().$vm.$locale = locale; + onLocaleChangeCallbacks.forEach((fn) => fn({ locale })); + return true; + } + return false; +}; +const onLocaleChangeCallbacks = []; +const onLocaleChange = (fn) => { + if (onLocaleChangeCallbacks.indexOf(fn) === -1) { + onLocaleChangeCallbacks.push(fn); + } +}; + const baseApis = { $on, $off, @@ -736,6 +760,9 @@ const baseApis = { addInterceptor, removeInterceptor, onAppLaunch, + getLocale, + setLocale, + onLocaleChange, }; function initUni(api, protocols) { const wrapper = initWrapper(protocols); @@ -929,7 +956,7 @@ function handleSystemInfo(fromRes, toRes) { } toRes.platform = platform; } -function returnValue(methodName, res) { +function returnValue(methodName, res = {}) { // 通用 returnValue 解析 if (res.error || res.errorMessage) { res.errMsg = `${methodName}:fail ${res.errorMessage || res.error}`; @@ -1107,8 +1134,18 @@ const connectSocket = { // TODO 有没有返回值还需要测试下 }; const chooseImage = { - returnValue: { - apFilePaths: 'tempFilePaths', + returnValue(result) { + var _a, _b; + const hasTempFilePaths = hasOwn(result, 'tempFilePaths') && result.tempFilePaths; + if (hasOwn(result, 'apFilePaths') && !hasTempFilePaths) { + result.tempFilePaths = []; + (_a = result.apFilePaths) === null || _a === void 0 ? void 0 : _a.forEach((apFilePath) => { var _a; return (_a = result.tempFilePaths) === null || _a === void 0 ? void 0 : _a.push(apFilePath); }); + } + if (!hasOwn(result, 'tempFiles') && hasTempFilePaths) { + result.tempFiles = []; + (_b = result.tempFilePaths) === null || _b === void 0 ? void 0 : _b.forEach((tempFilePath) => { var _a; return (_a = result.tempFiles) === null || _a === void 0 ? void 0 : _a.push({ path: tempFilePath }); }); + } + return {}; }, }; const previewImage = { diff --git a/packages/uni-mp-alipay/dist/uni.mp.esm.js b/packages/uni-mp-alipay/dist/uni.mp.esm.js index a04f9acf3..93b8781bc 100644 --- a/packages/uni-mp-alipay/dist/uni.mp.esm.js +++ b/packages/uni-mp-alipay/dist/uni.mp.esm.js @@ -1,5 +1,5 @@ import { isPlainObject, isArray, extend, hyphenate, isObject, hasOwn, toNumber, capitalize, isFunction, NOOP, EMPTY_OBJ, camelize } from '@vue/shared'; -import { onUnmounted, injectHook } from 'vue'; +import { onUnmounted, injectHook, ref } from 'vue'; const encode = encodeURIComponent; function stringifyQuery(obj, encodeStr = encode) { @@ -578,6 +578,7 @@ function parseApp(instance, parseAppOptions) { instance.$callHook(ON_LAUNCH, extend({ app: this }, options)); }, }; + initLocale(instance); const vueOptions = instance.$.type; initHooks(appOptions, HOOKS); initUnknownHooks(appOptions, vueOptions); @@ -594,6 +595,17 @@ function initCreateApp(parseAppOptions) { return function createApp(vm) { return App(parseApp(vm, parseAppOptions)); }; +} +function initLocale(appVm) { + const locale = ref(uni.getSystemInfoSync().language || 'zh-Hans'); + Object.defineProperty(appVm, '$locale', { + get() { + return locale.value; + }, + set(v) { + locale.value = v; + }, + }); } const PROP_TYPES = [String, Number, Boolean, Object, Array, null]; diff --git a/packages/uni-mp-baidu/dist/uni.api.esm.js b/packages/uni-mp-baidu/dist/uni.api.esm.js index d60c8db10..65a5f1308 100644 --- a/packages/uni-mp-baidu/dist/uni.api.esm.js +++ b/packages/uni-mp-baidu/dist/uni.api.esm.js @@ -583,7 +583,7 @@ const $emit = defineSyncApi(API_EMIT, (name, ...args) => { emitter.emit(name, ...args); }, EmitProtocol); -const SYNC_API_RE = /^\$|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; +const SYNC_API_RE = /^\$|getLocale|setLocale|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; const CONTEXT_API_RE = /^create|Manager$/; // Context例外情况 const CONTEXT_API_RE_EXC = ['createBLEConnection']; @@ -727,6 +727,30 @@ function initWrapper(protocols) { }; } +const getLocale = () => { + // 优先使用 $locale + const app = getApp({ allowDefault: true }); + if (app && app.$vm) { + return app.$vm.$locale; + } + return uni.getSystemInfoSync().language || 'zh-Hans'; +}; +const setLocale = (locale) => { + const oldLocale = getApp().$vm.$locale; + if (oldLocale !== locale) { + getApp().$vm.$locale = locale; + onLocaleChangeCallbacks.forEach((fn) => fn({ locale })); + return true; + } + return false; +}; +const onLocaleChangeCallbacks = []; +const onLocaleChange = (fn) => { + if (onLocaleChangeCallbacks.indexOf(fn) === -1) { + onLocaleChangeCallbacks.push(fn); + } +}; + const baseApis = { $on, $off, @@ -736,6 +760,9 @@ const baseApis = { addInterceptor, removeInterceptor, onAppLaunch, + getLocale, + setLocale, + onLocaleChange, }; function initUni(api, protocols) { const wrapper = initWrapper(protocols); diff --git a/packages/uni-mp-baidu/dist/uni.mp.esm.js b/packages/uni-mp-baidu/dist/uni.mp.esm.js index 5b4735415..bcaa5f734 100644 --- a/packages/uni-mp-baidu/dist/uni.mp.esm.js +++ b/packages/uni-mp-baidu/dist/uni.mp.esm.js @@ -1,5 +1,5 @@ import { isPlainObject, hasOwn, isArray, extend, hyphenate, isObject, toNumber, isFunction, NOOP, camelize } from '@vue/shared'; -import { onUnmounted, injectHook } from 'vue'; +import { onUnmounted, injectHook, ref } from 'vue'; const encode = encodeURIComponent; function stringifyQuery(obj, encodeStr = encode) { @@ -603,6 +603,7 @@ function parseApp(instance, parseAppOptions) { instance.$callHook(ON_LAUNCH, extend({ app: this }, options)); }, }; + initLocale(instance); const vueOptions = instance.$.type; initHooks(appOptions, HOOKS); initUnknownHooks(appOptions, vueOptions); @@ -619,6 +620,17 @@ function initCreateApp(parseAppOptions) { return function createApp(vm) { return App(parseApp(vm, parseAppOptions)); }; +} +function initLocale(appVm) { + const locale = ref(uni.getSystemInfoSync().language || 'zh-Hans'); + Object.defineProperty(appVm, '$locale', { + get() { + return locale.value; + }, + set(v) { + locale.value = v; + }, + }); } const PROP_TYPES = [String, Number, Boolean, Object, Array, null]; @@ -1179,6 +1191,45 @@ var parseAppOptions = /*#__PURE__*/Object.freeze({ parse: parse$2 }); +/** + * 用于延迟调用 setData + * 在 setData 真实调用的时机需执行 fixSetDataEnd + * @param {*} mpInstance + */ +function fixSetDataStart(mpInstance) { + const setData = mpInstance.setData; + const setDataArgs = []; + mpInstance.setData = function () { + setDataArgs.push(arguments); + }; + mpInstance.__fixInitData = function () { + this.setData = setData; + const fn = () => { + setDataArgs.forEach((args) => { + setData.apply(this, args); + }); + }; + if (setDataArgs.length) { + if (this.groupSetData) { + this.groupSetData(fn); + } + else { + fn(); + } + } + }; +} +/** + * 恢复真实的 setData 方法 + * @param {*} mpInstance + */ +function fixSetDataEnd(mpInstance) { + if (mpInstance.__fixInitData) { + mpInstance.__fixInitData(); + delete mpInstance.__fixInitData; + } +} + function initLifetimes({ mocks, isPage, initRelation, vueOptions, }) { return { attached() { @@ -1250,10 +1301,29 @@ function parse$1(componentOptions) { // lifetimes:attached --> methods:onShow --> methods:onLoad --> methods:onReady // 这里在强制将onShow挪到onLoad之后触发,另外一处修改在page-parser.js const oldAttached = lifetimes.attached; - lifetimes.attached = function attached() { + // 百度小程序基础库 3.260 以上支持页面 onInit 生命周期,提前创建 vm 实例 + lifetimes.onInit = function onInit(query) { + // 百度小程序后续可能移除 pageinstance 属性,为向后兼容进行补充 + if (!this.pageinstance || !this.pageinstance.setData) { + const pages = getCurrentPages(); + this.pageinstance = pages[pages.length - 1]; + } + // 处理百度小程序 onInit 生命周期调用 setData 无效的问题 + fixSetDataStart(this); oldAttached.call(this); + this.pageinstance.$vm = this.$vm; + this.$vm.__call_hook('onInit', query); + }; + lifetimes.attached = function attached() { + if (!this.$vm) { + oldAttached.call(this); + } + else { + initMocks(this.$vm.$, this, mocks); + fixSetDataEnd(this); + } if (isPage(this) && this.$vm) { - // 百度 onLoad 在 attached 之前触发 + // 百度 onLoad 在 attached 之前触发(基础库小于 3.70) // 百度 当组件作为页面时 pageinstance 不是原来组件的 instance const pageInstance = this.pageinstance; pageInstance.$vm = this.$vm; diff --git a/packages/uni-mp-kuaishou/dist/uni.api.esm.js b/packages/uni-mp-kuaishou/dist/uni.api.esm.js index a71abe197..7ad77fc21 100644 --- a/packages/uni-mp-kuaishou/dist/uni.api.esm.js +++ b/packages/uni-mp-kuaishou/dist/uni.api.esm.js @@ -583,7 +583,7 @@ const $emit = defineSyncApi(API_EMIT, (name, ...args) => { emitter.emit(name, ...args); }, EmitProtocol); -const SYNC_API_RE = /^\$|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; +const SYNC_API_RE = /^\$|getLocale|setLocale|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; const CONTEXT_API_RE = /^create|Manager$/; // Context例外情况 const CONTEXT_API_RE_EXC = ['createBLEConnection']; @@ -727,6 +727,30 @@ function initWrapper(protocols) { }; } +const getLocale = () => { + // 优先使用 $locale + const app = getApp({ allowDefault: true }); + if (app && app.$vm) { + return app.$vm.$locale; + } + return uni.getSystemInfoSync().language || 'zh-Hans'; +}; +const setLocale = (locale) => { + const oldLocale = getApp().$vm.$locale; + if (oldLocale !== locale) { + getApp().$vm.$locale = locale; + onLocaleChangeCallbacks.forEach((fn) => fn({ locale })); + return true; + } + return false; +}; +const onLocaleChangeCallbacks = []; +const onLocaleChange = (fn) => { + if (onLocaleChangeCallbacks.indexOf(fn) === -1) { + onLocaleChangeCallbacks.push(fn); + } +}; + const baseApis = { $on, $off, @@ -736,6 +760,9 @@ const baseApis = { addInterceptor, removeInterceptor, onAppLaunch, + getLocale, + setLocale, + onLocaleChange, }; function initUni(api, protocols) { const wrapper = initWrapper(protocols); diff --git a/packages/uni-mp-kuaishou/dist/uni.mp.esm.js b/packages/uni-mp-kuaishou/dist/uni.mp.esm.js index 860f9bf9a..87ce3029a 100644 --- a/packages/uni-mp-kuaishou/dist/uni.mp.esm.js +++ b/packages/uni-mp-kuaishou/dist/uni.mp.esm.js @@ -1,5 +1,5 @@ import { isPlainObject, hasOwn, isArray, extend, hyphenate, isObject, toNumber, isFunction, NOOP, camelize } from '@vue/shared'; -import { onUnmounted, injectHook } from 'vue'; +import { onUnmounted, injectHook, ref } from 'vue'; const encode = encodeURIComponent; function stringifyQuery(obj, encodeStr = encode) { @@ -603,6 +603,7 @@ function parseApp(instance, parseAppOptions) { instance.$callHook(ON_LAUNCH, extend({ app: this }, options)); }, }; + initLocale(instance); const vueOptions = instance.$.type; initHooks(appOptions, HOOKS); initUnknownHooks(appOptions, vueOptions); @@ -619,6 +620,17 @@ function initCreateApp(parseAppOptions) { return function createApp(vm) { return App(parseApp(vm, parseAppOptions)); }; +} +function initLocale(appVm) { + const locale = ref(uni.getSystemInfoSync().language || 'zh-Hans'); + Object.defineProperty(appVm, '$locale', { + get() { + return locale.value; + }, + set(v) { + locale.value = v; + }, + }); } const PROP_TYPES = [String, Number, Boolean, Object, Array, null]; diff --git a/packages/uni-mp-qq/dist/uni.api.esm.js b/packages/uni-mp-qq/dist/uni.api.esm.js index 6ee33ac8f..9941b76b8 100644 --- a/packages/uni-mp-qq/dist/uni.api.esm.js +++ b/packages/uni-mp-qq/dist/uni.api.esm.js @@ -583,7 +583,7 @@ const $emit = defineSyncApi(API_EMIT, (name, ...args) => { emitter.emit(name, ...args); }, EmitProtocol); -const SYNC_API_RE = /^\$|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; +const SYNC_API_RE = /^\$|getLocale|setLocale|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; const CONTEXT_API_RE = /^create|Manager$/; // Context例外情况 const CONTEXT_API_RE_EXC = ['createBLEConnection']; @@ -727,6 +727,30 @@ function initWrapper(protocols) { }; } +const getLocale = () => { + // 优先使用 $locale + const app = getApp({ allowDefault: true }); + if (app && app.$vm) { + return app.$vm.$locale; + } + return uni.getSystemInfoSync().language || 'zh-Hans'; +}; +const setLocale = (locale) => { + const oldLocale = getApp().$vm.$locale; + if (oldLocale !== locale) { + getApp().$vm.$locale = locale; + onLocaleChangeCallbacks.forEach((fn) => fn({ locale })); + return true; + } + return false; +}; +const onLocaleChangeCallbacks = []; +const onLocaleChange = (fn) => { + if (onLocaleChangeCallbacks.indexOf(fn) === -1) { + onLocaleChangeCallbacks.push(fn); + } +}; + const baseApis = { $on, $off, @@ -736,6 +760,9 @@ const baseApis = { addInterceptor, removeInterceptor, onAppLaunch, + getLocale, + setLocale, + onLocaleChange, }; function initUni(api, protocols) { const wrapper = initWrapper(protocols); diff --git a/packages/uni-mp-qq/dist/uni.mp.esm.js b/packages/uni-mp-qq/dist/uni.mp.esm.js index ea73fc1e3..d21075e70 100644 --- a/packages/uni-mp-qq/dist/uni.mp.esm.js +++ b/packages/uni-mp-qq/dist/uni.mp.esm.js @@ -1,5 +1,5 @@ import { isPlainObject, hasOwn, isArray, extend, hyphenate, isObject, toNumber, isFunction, NOOP, camelize } from '@vue/shared'; -import { onUnmounted, injectHook } from 'vue'; +import { onUnmounted, injectHook, ref } from 'vue'; const encode = encodeURIComponent; function stringifyQuery(obj, encodeStr = encode) { @@ -603,6 +603,7 @@ function parseApp(instance, parseAppOptions) { instance.$callHook(ON_LAUNCH, extend({ app: this }, options)); }, }; + initLocale(instance); const vueOptions = instance.$.type; initHooks(appOptions, HOOKS); initUnknownHooks(appOptions, vueOptions); @@ -619,6 +620,17 @@ function initCreateApp(parseAppOptions) { return function createApp(vm) { return App(parseApp(vm, parseAppOptions)); }; +} +function initLocale(appVm) { + const locale = ref(uni.getSystemInfoSync().language || 'zh-Hans'); + Object.defineProperty(appVm, '$locale', { + get() { + return locale.value; + }, + set(v) { + locale.value = v; + }, + }); } const PROP_TYPES = [String, Number, Boolean, Object, Array, null]; diff --git a/packages/uni-mp-toutiao/dist/uni.api.esm.js b/packages/uni-mp-toutiao/dist/uni.api.esm.js index 758ac002d..bae0f5268 100644 --- a/packages/uni-mp-toutiao/dist/uni.api.esm.js +++ b/packages/uni-mp-toutiao/dist/uni.api.esm.js @@ -583,7 +583,7 @@ const $emit = defineSyncApi(API_EMIT, (name, ...args) => { emitter.emit(name, ...args); }, EmitProtocol); -const SYNC_API_RE = /^\$|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; +const SYNC_API_RE = /^\$|getLocale|setLocale|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; const CONTEXT_API_RE = /^create|Manager$/; // Context例外情况 const CONTEXT_API_RE_EXC = ['createBLEConnection']; @@ -727,6 +727,30 @@ function initWrapper(protocols) { }; } +const getLocale = () => { + // 优先使用 $locale + const app = getApp({ allowDefault: true }); + if (app && app.$vm) { + return app.$vm.$locale; + } + return uni.getSystemInfoSync().language || 'zh-Hans'; +}; +const setLocale = (locale) => { + const oldLocale = getApp().$vm.$locale; + if (oldLocale !== locale) { + getApp().$vm.$locale = locale; + onLocaleChangeCallbacks.forEach((fn) => fn({ locale })); + return true; + } + return false; +}; +const onLocaleChangeCallbacks = []; +const onLocaleChange = (fn) => { + if (onLocaleChangeCallbacks.indexOf(fn) === -1) { + onLocaleChangeCallbacks.push(fn); + } +}; + const baseApis = { $on, $off, @@ -736,6 +760,9 @@ const baseApis = { addInterceptor, removeInterceptor, onAppLaunch, + getLocale, + setLocale, + onLocaleChange, }; function initUni(api, protocols) { const wrapper = initWrapper(protocols); diff --git a/packages/uni-mp-toutiao/dist/uni.mp.esm.js b/packages/uni-mp-toutiao/dist/uni.mp.esm.js index c8cc1366d..de97b6799 100644 --- a/packages/uni-mp-toutiao/dist/uni.mp.esm.js +++ b/packages/uni-mp-toutiao/dist/uni.mp.esm.js @@ -1,5 +1,5 @@ import { isPlainObject, hasOwn, isArray, extend, hyphenate, isObject, toNumber, isFunction, NOOP, camelize } from '@vue/shared'; -import { onUnmounted, injectHook } from 'vue'; +import { onUnmounted, injectHook, ref } from 'vue'; const encode = encodeURIComponent; function stringifyQuery(obj, encodeStr = encode) { @@ -606,6 +606,7 @@ function parseApp(instance, parseAppOptions) { instance.$callHook(ON_LAUNCH, extend({ app: this }, options)); }, }; + initLocale(instance); const vueOptions = instance.$.type; initHooks(appOptions, HOOKS); initUnknownHooks(appOptions, vueOptions); @@ -622,6 +623,17 @@ function initCreateApp(parseAppOptions) { return function createApp(vm) { return App(parseApp(vm, parseAppOptions)); }; +} +function initLocale(appVm) { + const locale = ref(uni.getSystemInfoSync().language || 'zh-Hans'); + Object.defineProperty(appVm, '$locale', { + get() { + return locale.value; + }, + set(v) { + locale.value = v; + }, + }); } const PROP_TYPES = [String, Number, Boolean, Object, Array, null]; diff --git a/packages/uni-mp-weixin/dist/uni.api.esm.js b/packages/uni-mp-weixin/dist/uni.api.esm.js index 429473fb0..d05147288 100644 --- a/packages/uni-mp-weixin/dist/uni.api.esm.js +++ b/packages/uni-mp-weixin/dist/uni.api.esm.js @@ -547,7 +547,7 @@ const $emit = defineSyncApi(API_EMIT, (name, ...args) => { emitter.emit(name, ...args); }, EmitProtocol); -const SYNC_API_RE = /^\$|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; +const SYNC_API_RE = /^\$|getLocale|setLocale|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; const CONTEXT_API_RE = /^create|Manager$/; // Context例外情况 const CONTEXT_API_RE_EXC = ['createBLEConnection']; @@ -691,6 +691,30 @@ function initWrapper(protocols) { }; } +const getLocale = () => { + // 优先使用 $locale + const app = getApp({ allowDefault: true }); + if (app && app.$vm) { + return app.$vm.$locale; + } + return uni.getSystemInfoSync().language || 'zh-Hans'; +}; +const setLocale = (locale) => { + const oldLocale = getApp().$vm.$locale; + if (oldLocale !== locale) { + getApp().$vm.$locale = locale; + onLocaleChangeCallbacks.forEach((fn) => fn({ locale })); + return true; + } + return false; +}; +const onLocaleChangeCallbacks = []; +const onLocaleChange = (fn) => { + if (onLocaleChangeCallbacks.indexOf(fn) === -1) { + onLocaleChangeCallbacks.push(fn); + } +}; + const baseApis = { $on, $off, @@ -700,6 +724,9 @@ const baseApis = { addInterceptor, removeInterceptor, onAppLaunch, + getLocale, + setLocale, + onLocaleChange, }; function initUni(api, protocols) { const wrapper = initWrapper(protocols); diff --git a/packages/uni-mp-weixin/dist/uni.mp.esm.js b/packages/uni-mp-weixin/dist/uni.mp.esm.js index e0ecaf665..4fcc49a7f 100644 --- a/packages/uni-mp-weixin/dist/uni.mp.esm.js +++ b/packages/uni-mp-weixin/dist/uni.mp.esm.js @@ -1,5 +1,5 @@ import { isPlainObject, hasOwn, isArray, extend, hyphenate, isObject, toNumber, isFunction, NOOP, camelize } from '@vue/shared'; -import { onUnmounted, injectHook } from 'vue'; +import { onUnmounted, injectHook, ref } from 'vue'; const encode = encodeURIComponent; function stringifyQuery(obj, encodeStr = encode) { @@ -549,6 +549,7 @@ function parseApp(instance, parseAppOptions) { instance.$callHook(ON_LAUNCH, extend({ app: this }, options)); }, }; + initLocale(instance); const vueOptions = instance.$.type; initHooks(appOptions, HOOKS); initUnknownHooks(appOptions, vueOptions); @@ -565,6 +566,17 @@ function initCreateApp(parseAppOptions) { return function createApp(vm) { return App(parseApp(vm, parseAppOptions)); }; +} +function initLocale(appVm) { + const locale = ref(uni.getSystemInfoSync().language || 'zh-Hans'); + Object.defineProperty(appVm, '$locale', { + get() { + return locale.value; + }, + set(v) { + locale.value = v; + }, + }); } const PROP_TYPES = [String, Number, Boolean, Object, Array, null]; diff --git a/packages/uni-quickapp-webview/dist/uni.api.esm.js b/packages/uni-quickapp-webview/dist/uni.api.esm.js index d6efb2763..44740deda 100644 --- a/packages/uni-quickapp-webview/dist/uni.api.esm.js +++ b/packages/uni-quickapp-webview/dist/uni.api.esm.js @@ -583,7 +583,7 @@ const $emit = defineSyncApi(API_EMIT, (name, ...args) => { emitter.emit(name, ...args); }, EmitProtocol); -const SYNC_API_RE = /^\$|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; +const SYNC_API_RE = /^\$|getLocale|setLocale|sendNativeEvent|restoreGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64/; const CONTEXT_API_RE = /^create|Manager$/; // Context例外情况 const CONTEXT_API_RE_EXC = ['createBLEConnection']; @@ -727,6 +727,30 @@ function initWrapper(protocols) { }; } +const getLocale = () => { + // 优先使用 $locale + const app = getApp({ allowDefault: true }); + if (app && app.$vm) { + return app.$vm.$locale; + } + return uni.getSystemInfoSync().language || 'zh-Hans'; +}; +const setLocale = (locale) => { + const oldLocale = getApp().$vm.$locale; + if (oldLocale !== locale) { + getApp().$vm.$locale = locale; + onLocaleChangeCallbacks.forEach((fn) => fn({ locale })); + return true; + } + return false; +}; +const onLocaleChangeCallbacks = []; +const onLocaleChange = (fn) => { + if (onLocaleChangeCallbacks.indexOf(fn) === -1) { + onLocaleChangeCallbacks.push(fn); + } +}; + const baseApis = { $on, $off, @@ -736,6 +760,9 @@ const baseApis = { addInterceptor, removeInterceptor, onAppLaunch, + getLocale, + setLocale, + onLocaleChange, }; function initUni(api, protocols) { const wrapper = initWrapper(protocols); diff --git a/packages/uni-quickapp-webview/dist/uni.mp.esm.js b/packages/uni-quickapp-webview/dist/uni.mp.esm.js index 84d914f82..5542f38f0 100644 --- a/packages/uni-quickapp-webview/dist/uni.mp.esm.js +++ b/packages/uni-quickapp-webview/dist/uni.mp.esm.js @@ -1,5 +1,5 @@ import { isPlainObject, hasOwn, isArray, extend, hyphenate, isObject, toNumber, isFunction, NOOP, camelize } from '@vue/shared'; -import { injectHook } from 'vue'; +import { injectHook, ref } from 'vue'; const encode = encodeURIComponent; function stringifyQuery(obj, encodeStr = encode) { @@ -534,6 +534,7 @@ function parseApp(instance, parseAppOptions) { instance.$callHook(ON_LAUNCH, extend({ app: this }, options)); }, }; + initLocale(instance); const vueOptions = instance.$.type; initHooks(appOptions, HOOKS); initUnknownHooks(appOptions, vueOptions); @@ -550,6 +551,17 @@ function initCreateApp(parseAppOptions) { return function createApp(vm) { return App(parseApp(vm, parseAppOptions)); }; +} +function initLocale(appVm) { + const locale = ref(uni.getSystemInfoSync().language || 'zh-Hans'); + Object.defineProperty(appVm, '$locale', { + get() { + return locale.value; + }, + set(v) { + locale.value = v; + }, + }); } const PROP_TYPES = [String, Number, Boolean, Object, Array, null]; -- GitLab