gemercheung 2 lat temu
rodzic
commit
2f11819628

+ 1 - 1
index.html

@@ -5,7 +5,7 @@
     <meta charset="utf-8" />
     <meta http-equiv="X-UA-Compatible" content="IE=edge" />
     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
-    <link rel="icon" href="<{BASE_URL}><{VITE_APP_STATIC_DIR}>/favicon.png" />
+    <link rel="icon" href="//4dkk.4dage.com/FDKKIMG/icon/kankan_icon.ico" />
 
     <link rel="stylesheet" href="//at.alicdn.com/t/font_2596172_ejg30arrayu.css" />
     <link rel="stylesheet" href="//at.alicdn.com/t/font_3423899_m7c62apktz.css" />

+ 1 - 0
package.json

@@ -22,6 +22,7 @@
     "trtc-js-sdk": "^4.14.6",
     "uuid": "^9.0.0",
     "vue": "^3.2.41",
+    "vue-i18n": "^9.2.2",
     "vue-types": "^4.2.1"
   },
   "devDependencies": {

+ 53 - 0
pnpm-lock.yaml

@@ -39,6 +39,7 @@ specifiers:
   vite-plugin-windicss: ^1.8.8
   vue: ^3.2.41
   vue-eslint-parser: ^9.1.0
+  vue-i18n: ^9.2.2
   vue-tsc: ^1.0.9
   vue-types: ^4.2.1
   windicss: ^3.5.6
@@ -53,6 +54,7 @@ dependencies:
   trtc-js-sdk: 4.14.6
   uuid: 9.0.0
   vue: 3.2.41
+  vue-i18n: 9.2.2_vue@3.2.41
   vue-types: 4.2.1_vue@3.2.41
 
 devDependencies:
@@ -557,6 +559,44 @@ packages:
     resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
     dev: true
 
+  /@intlify/core-base/9.2.2:
+    resolution: {integrity: sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==}
+    engines: {node: '>= 14'}
+    dependencies:
+      '@intlify/devtools-if': 9.2.2
+      '@intlify/message-compiler': 9.2.2
+      '@intlify/shared': 9.2.2
+      '@intlify/vue-devtools': 9.2.2
+    dev: false
+
+  /@intlify/devtools-if/9.2.2:
+    resolution: {integrity: sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==}
+    engines: {node: '>= 14'}
+    dependencies:
+      '@intlify/shared': 9.2.2
+    dev: false
+
+  /@intlify/message-compiler/9.2.2:
+    resolution: {integrity: sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==}
+    engines: {node: '>= 14'}
+    dependencies:
+      '@intlify/shared': 9.2.2
+      source-map: 0.6.1
+    dev: false
+
+  /@intlify/shared/9.2.2:
+    resolution: {integrity: sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==}
+    engines: {node: '>= 14'}
+    dev: false
+
+  /@intlify/vue-devtools/9.2.2:
+    resolution: {integrity: sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==}
+    engines: {node: '>= 14'}
+    dependencies:
+      '@intlify/core-base': 9.2.2
+      '@intlify/shared': 9.2.2
+    dev: false
+
   /@istanbuljs/load-nyc-config/1.1.0:
     resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
     engines: {node: '>=8'}
@@ -5764,6 +5804,19 @@ packages:
       - supports-color
     dev: true
 
+  /vue-i18n/9.2.2_vue@3.2.41:
+    resolution: {integrity: sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==}
+    engines: {node: '>= 14'}
+    peerDependencies:
+      vue: ^3.0.0
+    dependencies:
+      '@intlify/core-base': 9.2.2
+      '@intlify/shared': 9.2.2
+      '@intlify/vue-devtools': 9.2.2
+      '@vue/devtools-api': 6.4.5
+      vue: 3.2.41
+    dev: false
+
   /vue-template-compiler/2.7.13:
     resolution: {integrity: sha512-jYM6TClwDS9YqP48gYrtAtaOhRKkbYmbzE+Q51gX5YDr777n7tNI/IZk4QV4l/PjQPNh/FVa/E92sh/RqKMrog==}
     dependencies:

+ 1 - 1
src/components/chatRoom/controls/join.ts

@@ -51,7 +51,7 @@ export function handleJoin(data: any) {
       rtcStore.showBaseDialog(
         {
           title: '温馨提示',
-          desc: '当前房间已满员',
+          desc: '带看人数已满,可切换自由观看',
           okTxt: '自由观看',
           closeTxt: '取消',
         },

+ 4 - 1
src/components/chatRoom/memberList.vue

@@ -11,7 +11,10 @@
           <div class="memberItem" v-for="(i, idx) in data" :key="idx">
             <div class="userMsg">
               <div class="avatar" :class="`${role}`">
-                <img :src="i?.Avatar ? decodeURIComponent(i?.Avatar) : defaultAvatar" alt="" />
+                <img
+                  :src="i?.Avatar?.length ? decodeURIComponent(i?.Avatar) : defaultAvatar"
+                  alt=""
+                />
                 <div class="avatar-crown" v-show="i.Role === 'leader'"></div>
               </div>
               <div class="name">{{ i.Nickname }}</div>

+ 50 - 0
src/hooks/useI18n.ts

@@ -0,0 +1,50 @@
+import { i18n } from '/@/locales/setupI18n';
+
+type I18nGlobalTranslation = {
+  (key: string): string;
+  (key: string, locale: string): string;
+  (key: string, locale: string, list: unknown[]): string;
+  (key: string, locale: string, named: Record<string, unknown>): string;
+  (key: string, list: unknown[]): string;
+  (key: string, named: Record<string, unknown>): string;
+};
+
+type I18nTranslationRestParameters = [string, any];
+
+function getKey(namespace: string | undefined, key: string) {
+  if (!namespace) {
+    return key;
+  }
+  if (key.startsWith(namespace)) {
+    return key;
+  }
+  return `${namespace}.${key}`;
+}
+
+export function useI18n(namespace?: string): {
+  t: I18nGlobalTranslation;
+} {
+  const normalFn = {
+    t: (key: string) => {
+      return getKey(namespace, key);
+    },
+  };
+
+  if (!i18n) {
+    return normalFn;
+  }
+
+  const { t, ...methods } = i18n.global;
+
+  const tFn: I18nGlobalTranslation = (key: string, ...arg: any[]) => {
+    if (!key) return '';
+    if (!key.includes('.') && !namespace) return key;
+    return t(getKey(namespace, key), ...(arg as I18nTranslationRestParameters));
+  };
+  return {
+    ...methods,
+    t: tFn,
+  };
+}
+
+export const t = (key: string) => key;

+ 37 - 0
src/locale/helper.ts

@@ -0,0 +1,37 @@
+import type { LocaleType } from '/#/config';
+
+import { set } from 'lodash-es';
+
+export const loadLocalePool: LocaleType[] = [];
+
+export function setHtmlPageLang(locale: LocaleType) {
+  document.querySelector('html')?.setAttribute('lang', locale);
+}
+
+export function setLoadLocalePool(cb: (loadLocalePool: LocaleType[]) => void) {
+  cb(loadLocalePool);
+}
+
+export function genMessage(langs: Record<string, Record<string, any>>, prefix = 'lang') {
+  const obj: Recordable = {};
+
+  Object.keys(langs).forEach((key) => {
+    const langFileModule = langs[key].default;
+    let fileName = key.replace(`./${prefix}/`, '').replace(/^\.\//, '');
+    const lastIndex = fileName.lastIndexOf('.');
+    fileName = fileName.substring(0, lastIndex);
+    const keyList = fileName.split('/');
+    const moduleName = keyList.shift();
+    const objKey = keyList.join('.');
+
+    if (moduleName) {
+      if (objKey) {
+        set(obj, moduleName, obj[moduleName] || {});
+        set(obj[moduleName], objKey, langFileModule);
+      } else {
+        set(obj, moduleName, langFileModule || {});
+      }
+    }
+  });
+  return obj;
+}

+ 3 - 0
src/locale/lang/en/index.ts

@@ -0,0 +1,3 @@
+export default {
+  name: 'test',
+};

+ 3 - 0
src/locale/lang/zh-CN/index.ts

@@ -0,0 +1,3 @@
+export default {
+  name: '测试',
+};

+ 44 - 0
src/locale/setupI18n.ts

@@ -0,0 +1,44 @@
+import type { App } from 'vue';
+import type { I18n, I18nOptions } from 'vue-i18n';
+
+import { createI18n } from 'vue-i18n';
+import { setHtmlPageLang, setLoadLocalePool } from './helper';
+import { localeSetting } from '/@/settings/localeSetting';
+import { useLocaleStoreWithOut } from '/@/store/modules/locale';
+
+const { fallback, availableLocales } = localeSetting;
+
+export let i18n: ReturnType<typeof createI18n>;
+
+async function createI18nOptions(): Promise<I18nOptions> {
+  const localeStore = useLocaleStoreWithOut();
+  const locale = localeStore.getLocale;
+  const defaultLocal = await import(`./lang/${locale}.ts`);
+  const message = defaultLocal.default?.message ?? {};
+
+  setHtmlPageLang(locale);
+  setLoadLocalePool((loadLocalePool) => {
+    loadLocalePool.push(locale);
+  });
+
+  return {
+    legacy: false,
+    locale,
+    fallbackLocale: fallback,
+    messages: {
+      [locale]: message,
+    },
+    availableLocales: availableLocales,
+    sync: true, //If you don’t want to inherit locale from global scope, you need to set sync of i18n component option to false.
+    silentTranslationWarn: true, // true - warning off
+    missingWarn: false,
+    silentFallbackWarn: true,
+  };
+}
+
+// setup i18n instance with glob
+export async function setupI18n(app: App) {
+  const options = await createI18nOptions();
+  i18n = createI18n(options) as I18n;
+  app.use(i18n);
+}

+ 69 - 0
src/locale/useLocale.ts

@@ -0,0 +1,69 @@
+/**
+ * Multi-language related operations
+ */
+import type { LocaleType } from '/#/config';
+
+import { i18n } from './setupI18n';
+import { useLocaleStoreWithOut } from '/@/store/modules/locale';
+import { unref, computed } from 'vue';
+import { loadLocalePool, setHtmlPageLang } from './helper';
+
+interface LangModule {
+  message: Recordable;
+  dateLocale: Recordable;
+  dateLocaleName: string;
+}
+
+function setI18nLanguage(locale: LocaleType) {
+  const localeStore = useLocaleStoreWithOut();
+
+  if (i18n.mode === 'legacy') {
+    i18n.global.locale = locale;
+  } else {
+    (i18n.global.locale as any).value = locale;
+  }
+  localeStore.setLocaleInfo({ locale });
+  setHtmlPageLang(locale);
+}
+
+export function useLocale() {
+  const localeStore = useLocaleStoreWithOut();
+  const getLocale = computed(() => localeStore.getLocale);
+  // const getShowLocalePicker = computed(() => localeStore.getShowPicker);
+
+  // const getAntdLocale = computed((): any => {
+  //   return i18n.global.getLocaleMessage(unref(getLocale))?.antdLocale ?? {};
+  // });
+
+  // Switching the language will change the locale of useI18n
+  // And submit to configuration modification
+  async function changeLocale(locale: LocaleType) {
+    const globalI18n = i18n.global;
+    const currentLocale = unref(globalI18n.locale);
+    if (currentLocale === locale) {
+      return locale;
+    }
+
+    if (loadLocalePool.includes(locale)) {
+      setI18nLanguage(locale);
+      return locale;
+    }
+    const langModule = ((await import(`./lang/${locale}.ts`)) as any).default as LangModule;
+    if (!langModule) return;
+
+    const { message } = langModule;
+
+    globalI18n.setLocaleMessage(locale, message);
+    loadLocalePool.push(locale);
+
+    setI18nLanguage(locale);
+    return locale;
+  }
+
+  return {
+    getLocale,
+    // getShowLocalePicker,
+    changeLocale,
+    // getAntdLocale,
+  };
+}

+ 27 - 0
src/setting/localeSetting.ts

@@ -0,0 +1,27 @@
+import type { LocaleSetting, LocaleType } from '/#/config';
+
+export const LOCALE: { [key: string]: LocaleType } = {
+  ZH_CN: 'zh_CN',
+  EN_US: 'en',
+};
+
+export const localeSetting: LocaleSetting = {
+  // Locale
+  locale: LOCALE.ZH_CN,
+  // Default locale
+  fallback: LOCALE.ZH_CN,
+  // available Locales
+  availableLocales: [LOCALE.ZH_CN, LOCALE.EN_US],
+};
+
+// locale list
+// export const localeList: DropMenu[] = [
+//   {
+//     text: '简体中文',
+//     event: LOCALE.ZH_CN,
+//   },
+//   {
+//     text: 'English',
+//     event: LOCALE.EN_US,
+//   },
+// ];

+ 52 - 0
src/store/modules/locale.ts

@@ -0,0 +1,52 @@
+import type { LocaleSetting, LocaleType } from '/#/config';
+
+import { defineStore } from 'pinia';
+import { store } from '/@/store';
+
+interface LocaleState {
+  localInfo: LocaleSetting;
+}
+
+export const useLocaleStore = defineStore({
+  id: 'app-locale',
+  state: (): LocaleState => ({
+    localInfo: {
+      locale: 'zh_CN',
+      // default language
+      fallback: 'zh_CN',
+      // available Locales
+      availableLocales: ['zh_CN', 'en'],
+    },
+  }),
+  persist: {
+    storage: localStorage,
+    paths: ['localInfo'],
+  },
+  getters: {
+    getLocale(): LocaleType {
+      return this.localInfo?.locale ?? 'zh_CN';
+    },
+  },
+  actions: {
+    /**
+     * Set up multilingual information and cache
+     * @param info multilingual info
+     */
+    setLocaleInfo(info: Partial<LocaleSetting>) {
+      this.localInfo = { ...this.localInfo, ...info };
+    },
+    /**
+     * Initialize multilingual information and load the existing configuration from the local cache
+     */
+    initLocale() {
+      this.setLocaleInfo({
+        ...this.localInfo,
+      });
+    },
+  },
+});
+
+// Need to be used outside the setup
+export function useLocaleStoreWithOut() {
+  return useLocaleStore(store);
+}

+ 11 - 0
types/config.d.ts

@@ -0,0 +1,11 @@
+export type LocaleType = 'zh_CN' | 'en' | 'ru' | 'ja' | 'ko';
+
+export interface LocaleSetting {
+  // showPicker: boolean;
+  // Current language
+  locale: LocaleType;
+  // default language
+  fallback: LocaleType;
+  // available Locales
+  availableLocales: LocaleType[];
+}