Refine i18n support (#236)
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"type": "patch",
|
||||
"comment": "refine i18n support",
|
||||
"packageName": "@acedatacloud/nexior",
|
||||
"email": "cqc@cuiqingcai.com",
|
||||
"dependentChangeType": "patch"
|
||||
}
|
||||
+3
-3
@@ -12,12 +12,12 @@
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
"build": "npm run build:web",
|
||||
"build:web": "cross-env VITE_SURFACE=web vite build",
|
||||
"build:web": "cross-env VITE_SURFACE=web vue-tsc -b && vite build",
|
||||
"build:android": "cross-env VITE_SURFACE=android vite build",
|
||||
"build:ios": "cross-env VITE_SURFACE=ios vite build",
|
||||
"pack:android": "npm run build:android && npx cap copy android",
|
||||
"pack:ios": "npm run build:ios && npx cap copy ios",
|
||||
"serve": "vite preview",
|
||||
"preview": "vite preview",
|
||||
"translate": "transmart",
|
||||
"lint": "eslint src --fix --ext .ts,.tsx,.vue,.js,.jsx",
|
||||
"prettier": "prettier --write .",
|
||||
@@ -64,7 +64,7 @@
|
||||
"uuid": "^8.3.2",
|
||||
"vue": "^3.5.17",
|
||||
"vue-codemirror": "^6.1.1",
|
||||
"vue-i18n": "^9.1.7",
|
||||
"vue-i18n": "^11.1.11",
|
||||
"vue-qrcode": "^2.2.0",
|
||||
"vue-router": "^4.5.1",
|
||||
"vuex": "^4.1.0",
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import { ElConfigProvider, ElTag } from 'element-plus';
|
||||
import AuthPanel from './components/common/AuthPanel.vue';
|
||||
import locale from 'element-plus/dist/locale/zh-cn.mjs';
|
||||
import locale from 'element-plus/es/locale/lang/en';
|
||||
import { isTest } from '@/constants/endpoint';
|
||||
|
||||
export default defineComponent({
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
<template>
|
||||
<el-dialog :model-value="visible" :width="300" class="text-center" @close="$emit('close')">
|
||||
<el-select v-model="value" @change="onSelectLocale">
|
||||
<el-option
|
||||
v-for="(locale, localeIndex) in locales"
|
||||
:key="localeIndex"
|
||||
:label="locale.label"
|
||||
:value="locale.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { ElDialog, ElSelect, ElOption } from 'element-plus';
|
||||
import { SUPPORTED_LOCALES, setI18nLanguage } from '@/i18n';
|
||||
import { setCookie } from 'typescript-cookie';
|
||||
import { getDomain } from '@/utils/initializer';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LocaleSelector',
|
||||
components: {
|
||||
ElDialog,
|
||||
ElSelect,
|
||||
ElOption
|
||||
},
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
emits: ['close'],
|
||||
data() {
|
||||
return {
|
||||
value: this.$i18n.locale,
|
||||
locales: SUPPORTED_LOCALES
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async onSelectLocale(locale: string) {
|
||||
// change router
|
||||
this.$router.push({ query: { ...this.$route.query, locale: undefined } });
|
||||
await setI18nLanguage(locale);
|
||||
this.setCookie(locale);
|
||||
window.location.reload();
|
||||
},
|
||||
setCookie(locale: string) {
|
||||
setCookie('LOCALE', locale, {
|
||||
path: '/',
|
||||
domain: getDomain()
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.icon {
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
margin-top: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
@@ -3,7 +3,14 @@
|
||||
<el-row class="paycodes">
|
||||
<el-col :span="12">
|
||||
<div class="paycode wechat">
|
||||
<qr-code v-if="modelValue?.pay_url" :value="modelValue?.pay_url" :size="200" class="qrcode m-auto" />
|
||||
<qr-code
|
||||
v-if="modelValue?.pay_url"
|
||||
:value="modelValue?.pay_url"
|
||||
:size="200"
|
||||
class="qrcode m-auto"
|
||||
type="image/png"
|
||||
:color="{ dark: '#000000', light: '#ffffff' }"
|
||||
/>
|
||||
<p class="help-text">{{ $t('order.message.wechatPayHelp') }}</p>
|
||||
</div>
|
||||
</el-col>
|
||||
|
||||
@@ -18,12 +18,13 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import { ElDropdown, ElDropdownMenu, ElDropdownItem, ElIcon } from 'element-plus';
|
||||
import { ArrowDown } from '@element-plus/icons-vue';
|
||||
import { SUPPORTED_LOCALES, setI18nLanguage } from '@/i18n';
|
||||
import { setCookie } from 'typescript-cookie';
|
||||
import { getDomain } from '@/utils/initializer';
|
||||
import { I18N_SUPPORTED_LOCALES } from '@/constants/i18n';
|
||||
import { setI18nLanguage } from '@/i18n';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'LocaleSelector',
|
||||
name: 'Locale',
|
||||
components: {
|
||||
ElDropdown,
|
||||
ElDropdownMenu,
|
||||
@@ -33,7 +34,7 @@ export default defineComponent({
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
locales: SUPPORTED_LOCALES
|
||||
locales: I18N_SUPPORTED_LOCALES
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
export const I18N_DEFAULT_LOCALE = 'en';
|
||||
|
||||
export const I18N_SUPPORTED_LOCALES = [
|
||||
{ value: 'en', label: 'English' },
|
||||
{ value: 'de', label: 'Deutsch' },
|
||||
{ value: 'pt', label: 'Português' },
|
||||
{ value: 'es', label: 'Español' },
|
||||
{ value: 'fr', label: 'Français' },
|
||||
{ value: 'zh-CN', label: '简体中文' },
|
||||
{ value: 'zh-TW', label: '繁體中文' },
|
||||
{ value: 'it', label: 'Italiano' },
|
||||
{ value: 'ko', label: '한국어' },
|
||||
{ value: 'ja', label: '日本語' },
|
||||
{ value: 'ru', label: 'Русский' },
|
||||
{ value: 'pl', label: 'Polski' },
|
||||
{ value: 'fi', label: 'Suomi' },
|
||||
{ value: 'sv', label: 'Svenska' },
|
||||
{ value: 'el', label: 'Ελληνικά' },
|
||||
{ value: 'uk', label: 'Українська' },
|
||||
{ value: 'ar', label: 'العربية' },
|
||||
{ value: 'sr', label: 'Српски' }
|
||||
];
|
||||
|
||||
export const I18N_SCOPES = [
|
||||
'index',
|
||||
'api',
|
||||
'application',
|
||||
'qrart',
|
||||
'luma',
|
||||
'pika',
|
||||
'kling',
|
||||
'flux',
|
||||
'hailuo',
|
||||
'headshots',
|
||||
'suno',
|
||||
'common',
|
||||
'console',
|
||||
'credential',
|
||||
'distribution',
|
||||
'order',
|
||||
'proxy',
|
||||
'service',
|
||||
'usage',
|
||||
'user',
|
||||
'site',
|
||||
'chat',
|
||||
'midjourney'
|
||||
];
|
||||
+32
-78
@@ -1,56 +1,16 @@
|
||||
import { createI18n, I18n } from 'vue-i18n';
|
||||
import { nextTick } from 'vue';
|
||||
import { createI18n } from 'vue-i18n';
|
||||
import { I18N_DEFAULT_LOCALE, I18N_SCOPES, I18N_SUPPORTED_LOCALES } from '@/constants/i18n';
|
||||
import axios from 'axios';
|
||||
import { nextTick } from 'vue';
|
||||
|
||||
declare namespace Intl {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function getCanonicalLocales(locales: string | string[] | undefined): string[];
|
||||
}
|
||||
|
||||
export const DEFAULT_LOCALE = 'en';
|
||||
|
||||
export const SUPPORTED_LOCALES = [
|
||||
{ value: 'en', label: 'English' },
|
||||
{ value: 'de', label: 'Deutsch' },
|
||||
{ value: 'pt', label: 'Português' },
|
||||
{ value: 'es', label: 'Español' },
|
||||
{ value: 'fr', label: 'Français' },
|
||||
{ value: 'zh-CN', label: '简体中文' },
|
||||
{ value: 'zh-TW', label: '繁體中文' },
|
||||
{ value: 'it', label: 'Italiano' },
|
||||
{ value: 'ko', label: '한국어' },
|
||||
{ value: 'ja', label: '日本語' },
|
||||
{ value: 'ru', label: 'Русский' },
|
||||
{ value: 'pl', label: 'Polski' },
|
||||
{ value: 'fi', label: 'Suomi' },
|
||||
{ value: 'sv', label: 'Svenska' },
|
||||
{ value: 'el', label: 'Ελληνικά' },
|
||||
{ value: 'uk', label: 'Українська' },
|
||||
{ value: 'ar', label: 'العربية' },
|
||||
{ value: 'sr', label: 'Српски' }
|
||||
];
|
||||
|
||||
export const setupI18n = () => {
|
||||
// @ts-ignore
|
||||
const i18n: I18n = createI18n({});
|
||||
return i18n;
|
||||
};
|
||||
|
||||
export const i18n = setupI18n();
|
||||
|
||||
export const loadLocalResource = async (name: string, locale: string) => {
|
||||
try {
|
||||
const module = await import(`./${locale}/${name}.json`);
|
||||
return module.default;
|
||||
} catch (error) {
|
||||
const module = await import(`./${DEFAULT_LOCALE}/${name}.json`);
|
||||
return module.default;
|
||||
}
|
||||
};
|
||||
export const i18n = createI18n({
|
||||
legacy: true
|
||||
});
|
||||
|
||||
export const getLocale = (lang?: string): string => {
|
||||
const canonicalLang = Intl.getCanonicalLocales(lang || navigator.language)?.[0];
|
||||
const supportedLocales = SUPPORTED_LOCALES.map((locale) => locale.value);
|
||||
console.debug('canonicalLang', canonicalLang);
|
||||
const supportedLocales = I18N_SUPPORTED_LOCALES.map((locale) => locale.value);
|
||||
// if the canonical language is supported, use it
|
||||
if (canonicalLang && supportedLocales.includes(canonicalLang)) {
|
||||
console.debug('canonicalLang', canonicalLang);
|
||||
@@ -63,41 +23,35 @@ export const getLocale = (lang?: string): string => {
|
||||
return canonicalLangPrefix;
|
||||
}
|
||||
}
|
||||
return DEFAULT_LOCALE;
|
||||
return I18N_DEFAULT_LOCALE;
|
||||
};
|
||||
|
||||
export const loadLocaleMessages = async (i18n: I18n, locale: string) => {
|
||||
const names = [
|
||||
'index',
|
||||
'api',
|
||||
'application',
|
||||
'qrart',
|
||||
'luma',
|
||||
'pika',
|
||||
'kling',
|
||||
'flux',
|
||||
'hailuo',
|
||||
'headshots',
|
||||
'suno',
|
||||
'common',
|
||||
'console',
|
||||
'credential',
|
||||
'distribution',
|
||||
'order',
|
||||
'proxy',
|
||||
'service',
|
||||
'usage',
|
||||
'user',
|
||||
'site',
|
||||
'chat',
|
||||
'midjourney'
|
||||
];
|
||||
const messageLoaders = import.meta.glob('./**/*.json');
|
||||
|
||||
const promises = names.map((name) => loadLocalResource(name, locale));
|
||||
export const loadLocaleResource = async (name: string, locale: string) => {
|
||||
console.debug('loadLocaleResource', name, locale);
|
||||
const path = `./${locale}/${name}.json`;
|
||||
const loader = messageLoaders[path];
|
||||
if (!loader) {
|
||||
console.warn(`[i18n] Missing translation file: ${path}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const module: any = await loader();
|
||||
console.debug('loaded module', module);
|
||||
if (!module.default) {
|
||||
console.warn(`[i18n] Missing default export in translation file: ${path}`);
|
||||
return;
|
||||
}
|
||||
return module.default;
|
||||
};
|
||||
|
||||
export const loadLocaleMessages = async (locale: string) => {
|
||||
const promises = I18N_SCOPES.map((name) => loadLocaleResource(name, locale));
|
||||
const resources = await Promise.all(promises);
|
||||
|
||||
const messages: any = {};
|
||||
names.forEach((name, index) => {
|
||||
I18N_SCOPES.forEach((name, index) => {
|
||||
const resource = resources[index];
|
||||
for (const key in resource) {
|
||||
if (resource.hasOwnProperty(key)) {
|
||||
@@ -116,7 +70,7 @@ export const loadLocaleMessages = async (i18n: I18n, locale: string) => {
|
||||
export const setI18nLanguage = async (locale: string) => {
|
||||
// load locale messages
|
||||
if (!i18n.global.availableLocales.includes(locale)) {
|
||||
await loadLocaleMessages(i18n, locale);
|
||||
await loadLocaleMessages(locale);
|
||||
}
|
||||
|
||||
// set global locale
|
||||
|
||||
@@ -305,7 +305,6 @@ export default defineComponent({
|
||||
},
|
||||
async onRestoreConversation(id: string) {
|
||||
console.debug('onRestoreConversation id', id);
|
||||
this.$router.push({ ...this.$route, params: { id } });
|
||||
const conversation = this.conversations?.find((conversation: IChatConversation) => conversation.id === id);
|
||||
// change the model and model group
|
||||
const model = conversation?.model;
|
||||
|
||||
@@ -152,6 +152,8 @@
|
||||
:size="180"
|
||||
:margin="2"
|
||||
class="block mb-2 ml-auto mr-auto"
|
||||
type="image/png"
|
||||
:color="{ dark: '#000000', light: '#ffffff' }"
|
||||
/>
|
||||
<p class="mt-0">
|
||||
{{ $t('distribution.message.distributionQrDescription') }}
|
||||
|
||||
@@ -41,7 +41,6 @@ import {
|
||||
} from '@/router';
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
||||
import { getBaseUrlAuth, getBaseUrlPlatform } from '@/utils';
|
||||
import LocaleSelector from '@/components/common/LocaleSelector.vue';
|
||||
import HelpDialog from '@/components/common/HelpDialog.vue';
|
||||
|
||||
interface ILink {
|
||||
@@ -58,8 +57,7 @@ export default defineComponent({
|
||||
components: {
|
||||
ElImage,
|
||||
HelpDialog,
|
||||
FontAwesomeIcon,
|
||||
LocaleSelector
|
||||
FontAwesomeIcon
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
+3
-2
@@ -18,8 +18,9 @@ import site from './site';
|
||||
import profile from './profile';
|
||||
|
||||
import { ROUTE_CHATGPT_CONVERSATION_NEW } from './constants';
|
||||
import { DEFAULT_LOCALE, setI18nLanguage } from '@/i18n';
|
||||
import { getCookie } from 'typescript-cookie';
|
||||
import { I18N_DEFAULT_LOCALE } from '@/constants/i18n';
|
||||
import { getLocale, setI18nLanguage } from '@/i18n';
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@@ -51,7 +52,7 @@ const router = createRouter({
|
||||
});
|
||||
|
||||
router.beforeEach(async (_to, _from, next) => {
|
||||
const locale = getCookie('LOCALE') || DEFAULT_LOCALE;
|
||||
const locale = getLocale(getCookie('LOCALE') || I18N_DEFAULT_LOCALE);
|
||||
await setI18nLanguage(locale);
|
||||
return next();
|
||||
});
|
||||
|
||||
Vendored
+8
-6
@@ -6,7 +6,7 @@
|
||||
|
||||
import { ComponentCustomProperties } from 'vue';
|
||||
import { Router } from 'vue-router';
|
||||
import { I18n } from 'vue-i18n';
|
||||
import { I18n, VueI18n } from 'vue-i18n';
|
||||
import { Store } from 'vuex';
|
||||
import { IRootState } from './store/common/models';
|
||||
import type { Router, RouteLocationNormalizedLoaded } from 'vue-router';
|
||||
@@ -17,10 +17,7 @@ declare module '*.ico';
|
||||
declare module '*.css';
|
||||
declare module '*.scss';
|
||||
declare module '*.png';
|
||||
declare module '*.tpl' {
|
||||
const value: string;
|
||||
export default value;
|
||||
}
|
||||
declare module '*.tpl';
|
||||
|
||||
declare module '*.vue' {
|
||||
import { DefineComponent } from 'vue';
|
||||
@@ -28,9 +25,14 @@ declare module '*.vue' {
|
||||
export default component;
|
||||
}
|
||||
|
||||
// declare namespace Intl {
|
||||
// function getCanonicalLocales(locales: string | string[] | undefined): string[];
|
||||
// }
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
interface ComponentCustomProperties {
|
||||
$t: (key: string, ...args: unknown[]) => string;
|
||||
$t: VueI18n['t'];
|
||||
$i18n: VueI18n;
|
||||
$store: Store<IRootState>;
|
||||
$router: Router;
|
||||
$route: RouteLocationNormalizedLoaded;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { getCookie, setCookie } from 'typescript-cookie';
|
||||
import favicon from '@/assets/images/favicon.ico';
|
||||
import { getLocale } from '@/i18n';
|
||||
import { applyTheme } from './theme';
|
||||
import store from '@/store';
|
||||
import { IToken } from '@/models';
|
||||
import { parse } from 'psl';
|
||||
import { BASE_HOST_HUB, LOCALE_CURRENCY_MAPPING } from '@/constants';
|
||||
import { isOfficial, isSubOfficial, isWechatBrowser } from './is';
|
||||
import { getLocale } from '@/i18n';
|
||||
|
||||
export const getDomain = (host: string = window.location.hostname) => {
|
||||
const parsed = parse(host);
|
||||
|
||||
@@ -503,26 +503,26 @@
|
||||
resolved "https://registry.yarnpkg.com/@icon-park/vue-next/-/vue-next-1.4.2.tgz#818c048100401620e8112beb2636f10171b195cc"
|
||||
integrity sha512-+QklF255wkfBOabY+xw6FAI0Bwln/RhdwCunNy/9sKdKuChtaU67QZqU67KGAvZUTeeBgsL+yaHHxqfQeGZXEQ==
|
||||
|
||||
"@intlify/core-base@9.14.5":
|
||||
version "9.14.5"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-9.14.5.tgz#cfed631e98b34f4f6fe1312e6c02dd8ace180197"
|
||||
integrity sha512-5ah5FqZG4pOoHjkvs8mjtv+gPKYU0zCISaYNjBNNqYiaITxW8ZtVih3GS/oTOqN8d9/mDLyrjD46GBApNxmlsA==
|
||||
"@intlify/core-base@11.1.11":
|
||||
version "11.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/core-base/-/core-base-11.1.11.tgz#e36893a7d37a3a75fae30977fc58c1d8cf3c853f"
|
||||
integrity sha512-1Z0N8jTfkcD2Luq9HNZt+GmjpFe4/4PpZF3AOzoO1u5PTtSuXZcfhwBatywbfE2ieB/B5QHIoOFmCXY2jqVKEQ==
|
||||
dependencies:
|
||||
"@intlify/message-compiler" "9.14.5"
|
||||
"@intlify/shared" "9.14.5"
|
||||
"@intlify/message-compiler" "11.1.11"
|
||||
"@intlify/shared" "11.1.11"
|
||||
|
||||
"@intlify/message-compiler@9.14.5":
|
||||
version "9.14.5"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-9.14.5.tgz#03b0a358c93cb2eed95936531c8a5871fd3841b0"
|
||||
integrity sha512-IHzgEu61/YIpQV5Pc3aRWScDcnFKWvQA9kigcINcCBXN8mbW+vk9SK+lDxA6STzKQsVJxUPg9ACC52pKKo3SVQ==
|
||||
"@intlify/message-compiler@11.1.11":
|
||||
version "11.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/message-compiler/-/message-compiler-11.1.11.tgz#ba10641f86af0e991ac9def0385bd345c8f150fb"
|
||||
integrity sha512-7PC6neomoc/z7a8JRjPBbu0T2TzR2MQuY5kn2e049MP7+o32Ve7O8husylkA7K9fQRe4iNXZWTPnDJ6vZdtS1Q==
|
||||
dependencies:
|
||||
"@intlify/shared" "9.14.5"
|
||||
"@intlify/shared" "11.1.11"
|
||||
source-map-js "^1.0.2"
|
||||
|
||||
"@intlify/shared@9.14.5":
|
||||
version "9.14.5"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-9.14.5.tgz#2e42193b8356db20ee28c15d1ee6c8f0fda6c0b9"
|
||||
integrity sha512-9gB+E53BYuAEMhbCAxVgG38EZrk59sxBtv3jSizNL2hEWlgjBjAw1AwpLHtNaeda12pe6W20OGEa0TwuMSRbyQ==
|
||||
"@intlify/shared@11.1.11":
|
||||
version "11.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@intlify/shared/-/shared-11.1.11.tgz#6bba3b86617c05767356e4ca939c9e300563a083"
|
||||
integrity sha512-RIBFTIqxZSsxUqlcyoR7iiC632bq7kkOwYvZlvcVObHfrF4NhuKc4FKvu8iPCrEO+e3XsY7/UVpfgzg+M7ETzA==
|
||||
|
||||
"@ionic/cli-framework-output@^2.2.5":
|
||||
version "2.2.8"
|
||||
@@ -5541,13 +5541,13 @@ vue-eslint-parser@^8.0.1:
|
||||
lodash "^4.17.21"
|
||||
semver "^7.3.5"
|
||||
|
||||
vue-i18n@^9.1.7:
|
||||
version "9.14.5"
|
||||
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-9.14.5.tgz#72fbf4384b83a1c59ec9e01ff5d30224bd9150cf"
|
||||
integrity sha512-0jQ9Em3ymWngyiIkj0+c/k7WgaPO+TNzjKSNq9BvBQaKJECqn9cd9fL4tkDhB5G1QBskGl9YxxbDAhgbFtpe2g==
|
||||
vue-i18n@^11.1.11:
|
||||
version "11.1.11"
|
||||
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-11.1.11.tgz#b38ed214896540cf7a68932dfa565d9d4fbbffac"
|
||||
integrity sha512-LvyteQoXeQiuILbzqv13LbyBna/TEv2Ha+4ZWK2AwGHUzZ8+IBaZS0TJkCgn5izSPLcgZwXy9yyTrewCb2u/MA==
|
||||
dependencies:
|
||||
"@intlify/core-base" "9.14.5"
|
||||
"@intlify/shared" "9.14.5"
|
||||
"@intlify/core-base" "11.1.11"
|
||||
"@intlify/shared" "11.1.11"
|
||||
"@vue/devtools-api" "^6.5.0"
|
||||
|
||||
vue-qrcode@^2.2.0:
|
||||
|
||||
Reference in New Issue
Block a user