fix CJK fonts

This commit is contained in:
pa
2025-09-14 15:21:44 +09:00
committed by Natsumi
parent b0f0896dae
commit 875459689f
27 changed files with 330 additions and 263 deletions

View File

@@ -89,11 +89,6 @@
import { createGlobalStores } from './stores';
import { watchState } from './service/watchState';
import '@fontsource/noto-sans-kr';
import '@fontsource/noto-sans-jp';
import '@fontsource/noto-sans-sc';
import '@fontsource/noto-sans-tc';
import Login from './views/Login/Login.vue';
import NavMenu from './components/NavMenu.vue';
import Sidebar from './views/Sidebar/Sidebar.vue';

View File

@@ -162,12 +162,44 @@ html {
body {
font-family:
'ellipsis-font', 'Noto Sans KR', 'Noto Sans JP', 'Noto Sans TC',
'ellipsis-font', 'Noto Sans JP', 'Noto Sans KR', 'Noto Sans TC',
'Noto Sans SC', 'Meiryo UI', 'Malgun Gothic', 'Segoe UI', system-ui,
sans-serif;
margin: 0;
}
html[lang='ja'] body,
html[lang='ja'] * {
font-family:
'ellipsis-font', 'Noto Sans JP', 'Noto Sans KR', 'Noto Sans TC',
'Noto Sans SC', 'Meiryo UI', 'Malgun Gothic', 'Segoe UI', system-ui,
sans-serif;
}
html[lang='ko'] body,
html[lang='ko'] * {
font-family:
'ellipsis-font', 'Noto Sans KR', 'Noto Sans JP', 'Noto Sans TC',
'Noto Sans SC', 'Meiryo UI', 'Malgun Gothic', 'Segoe UI', system-ui,
sans-serif;
}
html[lang='zh-CN'] body,
html[lang='zh-CN'] * {
font-family:
'ellipsis-font', 'Noto Sans SC', 'Noto Sans TC', 'Noto Sans JP',
'Noto Sans KR', 'Meiryo UI', 'Malgun Gothic', 'Segoe UI', system-ui,
sans-serif;
}
html[lang='zh-TW'] body,
html[lang='zh-TW'] * {
font-family:
'ellipsis-font', 'Noto Sans TC', 'Noto Sans SC', 'Noto Sans JP',
'Noto Sans KR', 'Meiryo UI', 'Malgun Gothic', 'Segoe UI', system-ui,
sans-serif;
}
a {
color: #409eff;
}

12
src/bootstrap.js vendored
View File

@@ -1,3 +1,13 @@
import '@fontsource/noto-sans-kr/korean.css';
import '@fontsource/noto-sans-jp/japanese.css';
import '@fontsource/noto-sans-sc/chinese-simplified.css';
import '@fontsource/noto-sans-tc/chinese-traditional.css';
import '@fontsource/noto-sans-kr';
import '@fontsource/noto-sans-jp';
import '@fontsource/noto-sans-sc';
import '@fontsource/noto-sans-tc';
import configRepository from './service/config';
import vrcxJsonStorage from './service/jsonStorage';
@@ -7,7 +17,7 @@ import {
refreshCustomCss,
refreshCustomScript,
systemIsDarkMode
} from './shared/utils';
} from './shared/utils/base/ui';
import { i18n } from './plugin/i18n';
import { initNoty } from './plugin/noty';
import './plugin/ipc';

View File

@@ -607,7 +607,6 @@
import { avatarModerationRequest, avatarRequest, favoriteRequest, miscRequest } from '../../../api';
import { database } from '../../../service/database';
import {
getNextDialogIndex,
buildTreeData,
commaNumber,
copyToClipboard,
@@ -621,6 +620,7 @@
formatDateFilter,
textToHex
} from '../../../shared/utils';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { useAvatarStore, useFavoriteStore, useGalleryStore, useGameStore, useUserStore } from '../../../stores';
const ChangeAvatarImageDialog = defineAsyncComponent(() => import('./ChangeAvatarImageDialog.vue'));

View File

@@ -69,7 +69,7 @@
import { computed, nextTick, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { favoriteRequest } from '../../api';
import { getNextDialogIndex } from '../../shared/utils';
import { getNextDialogIndex } from '../../shared/utils/base/ui';
import { useFavoriteStore, useUserStore } from '../../stores';
const { t } = useI18n();

View File

@@ -1193,7 +1193,6 @@
import { groupRequest } from '../../../api';
import { groupDialogFilterOptions, groupDialogSortingOptions } from '../../../shared/constants';
import {
getNextDialogIndex,
buildTreeData,
copyToClipboard,
downloadAndSaveJson,
@@ -1210,6 +1209,7 @@
textToHex,
debounce
} from '../../../shared/utils';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { useGalleryStore, useGroupStore, useLocationStore, useUserStore } from '../../../stores';
import InviteGroupDialog from '../InviteGroupDialog.vue';
import GroupPostEditDialog from './GroupPostEditDialog.vue';

View File

@@ -170,7 +170,8 @@
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
import { groupRequest, userRequest } from '../../api';
import { getNextDialogIndex, hasGroupPermission, userImage, userStatusClass } from '../../shared/utils';
import { hasGroupPermission, userImage, userStatusClass } from '../../shared/utils';
import { getNextDialogIndex } from '../../shared/utils/base/ui';
import { useFriendStore, useGroupStore } from '../../stores';
const { vipFriends, onlineFriends, activeFriends, offlineFriends } = storeToRefs(useFriendStore());

View File

@@ -113,13 +113,8 @@
import { useI18n } from 'vue-i18n';
import { instanceRequest, worldRequest } from '../../api';
import configRepository from '../../service/config';
import {
getNextDialogIndex,
checkCanInvite,
getLaunchURL,
isRealInstance,
parseLocation
} from '../../shared/utils';
import { checkCanInvite, getLaunchURL, isRealInstance, parseLocation } from '../../shared/utils';
import { getNextDialogIndex } from '../../shared/utils/base/ui';
import {
useFriendStore,
useInviteStore,

View File

@@ -65,7 +65,8 @@
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
import { groupRequest, userRequest } from '../../api';
import { getNextDialogIndex, hasGroupModerationPermission, userImage } from '../../shared/utils';
import { hasGroupModerationPermission, userImage } from '../../shared/utils';
import { getNextDialogIndex } from '../../shared/utils/base/ui';
import { useGroupStore } from '../../stores';
const { currentUserGroups, moderateGroupDialog } = storeToRefs(useGroupStore());

View File

@@ -498,7 +498,6 @@
import { groupRequest, instanceRequest, worldRequest } from '../../api';
import configRepository from '../../service/config';
import {
getNextDialogIndex,
copyToClipboard,
getLaunchURL,
hasGroupPermission,
@@ -507,6 +506,7 @@
userImage,
userStatusClass
} from '../../shared/utils';
import { getNextDialogIndex } from '../../shared/utils/base/ui';
import {
useFriendStore,
useGroupStore,

View File

@@ -65,15 +65,15 @@
import { DataLine, Close } from '@element-plus/icons-vue';
import { ElMessageBox } from 'element-plus';
import { ref, reactive, computed, watch, nextTick, getCurrentInstance } from 'vue';
import { ref, reactive, computed, watch, nextTick } from 'vue';
import {
parseLocation,
compareByCreatedAt,
timeToText,
removeFromArray,
getNextDialogIndex,
formatDateFilter
} from '../../../shared/utils';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { database } from '../../../service/database';
import { useI18n } from 'vue-i18n';
import { useInstanceStore, useUiStore } from '../../../stores';

View File

@@ -63,13 +63,8 @@
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
import { database } from '../../../service/database';
import {
getNextDialogIndex,
compareByCreatedAt,
parseLocation,
timeToText,
formatDateFilter
} from '../../../shared/utils';
import { compareByCreatedAt, parseLocation, timeToText, formatDateFilter } from '../../../shared/utils';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { useGameLogStore, useInstanceStore, useUserStore } from '../../../stores';
const { lookupUser } = useUserStore();

View File

@@ -77,13 +77,13 @@
import { useI18n } from 'vue-i18n';
import { database } from '../../../service/database';
import {
getNextDialogIndex,
compareByCreatedAt,
parseLocation,
removeFromArray,
timeToText,
formatDateFilter
} from '../../../shared/utils';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { useInstanceStore, useUiStore, useUserStore } from '../../../stores';
const { t } = useI18n();

View File

@@ -80,13 +80,13 @@
import { useI18n } from 'vue-i18n';
import { database } from '../../../service/database';
import {
getNextDialogIndex,
compareByCreatedAt,
parseLocation,
removeFromArray,
timeToText,
formatDateFilter
} from '../../../shared/utils';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { useInstanceStore, useLaunchStore, useUiStore } from '../../../stores';
const props = defineProps({

View File

@@ -1810,14 +1810,11 @@
import { userDialogGroupSortingOptions } from '../../../shared/constants';
import { userDialogWorldOrderOptions, userDialogWorldSortingOptions } from '../../../shared/constants/';
import {
getNextDialogIndex,
checkCanInvite,
compareByMemberCount,
compareByName,
copyToClipboard,
downloadAndSaveJson,
extractFileId,
getFaviconUrl,
isFriendOnline,
isRealInstance,
languageClass,
@@ -1834,6 +1831,7 @@
textToHex,
formatDateFilter
} from '../../../shared/utils';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import {
useAdvancedSettingsStore,
useAppearanceSettingsStore,

View File

@@ -67,7 +67,7 @@
import { nextTick, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { branches } from '../../shared/constants';
import { getNextDialogIndex } from '../../shared/utils';
import { getNextDialogIndex } from '../../shared/utils/base/ui';
import { useVRCXUpdaterStore } from '../../stores';
const VRCXUpdaterStore = useVRCXUpdaterStore();

View File

@@ -786,7 +786,6 @@
import { favoriteRequest, miscRequest, userRequest, worldRequest } from '../../../api';
import { database } from '../../../service/database.js';
import {
getNextDialogIndex,
buildTreeData,
downloadAndSaveJson,
openExternalLink,
@@ -802,6 +801,8 @@
textToHex,
copyToClipboard
} from '../../../shared/utils';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import {
useAppearanceSettingsStore,
useFavoriteStore,

View File

@@ -217,6 +217,11 @@ function getNextDialogIndex() {
return z + 1;
}
function changeHtmlLangAttribute(language) {
const htmlElement = document.documentElement;
htmlElement.setAttribute('lang', language);
}
export {
systemIsDarkMode,
changeAppDarkStyle,
@@ -226,5 +231,6 @@ export {
refreshCustomScript,
HueToHex,
HSVtoRGB,
getNextDialogIndex
getNextDialogIndex,
changeHtmlLangAttribute
};

View File

@@ -3,7 +3,6 @@ export * from './base/devtool';
export * from './base/format';
export * from './base/date';
export * from './base/string';
export * from './base/ui';
export * from './avatar';
export * from './chart';
export * from './common';

View File

@@ -6,14 +6,15 @@ import { ElMessageBox } from 'element-plus';
import configRepository from '../../service/config';
import { database } from '../../service/database';
import { watchState } from '../../service/watchState';
import { getNameColour } from '../../shared/utils';
import {
changeAppDarkStyle,
changeAppThemeStyle,
getNameColour,
HueToHex,
systemIsDarkMode,
updateTrustColorClasses
} from '../../shared/utils';
updateTrustColorClasses,
changeHtmlLangAttribute
} from '../../shared/utils/base/ui';
import { useFeedStore } from '../feed';
import { useFriendStore } from '../friend';
import { useGameLogStore } from '../gameLog';
@@ -277,8 +278,7 @@ export const useAppearanceSettingsStore = defineStore(
state.appLanguage = language;
configRepository.setString('VRCX_appLanguage', language);
locale.value = state.appLanguage;
const htmlElement = document.documentElement;
htmlElement.setAttribute('lang', state.appLanguage);
changeHtmlLangAttribute(language);
}
/**

View File

@@ -7,7 +7,8 @@ import { database } from '../service/database';
import { AppDebug } from '../service/appConfig';
import { failedGetRequests } from '../service/request';
import { watchState } from '../service/watchState';
import { debounce, parseLocation, refreshCustomCss } from '../shared/utils';
import { debounce, parseLocation } from '../shared/utils';
import { refreshCustomCss } from '../shared/utils/base/ui';
import { useAvatarStore } from './avatar';
import { useAvatarProviderStore } from './avatarProvider';
import { useFavoriteStore } from './favorite';

View File

@@ -183,7 +183,8 @@
import { useI18n } from 'vue-i18n';
import { storeToRefs } from 'pinia';
import { avatarRequest, favoriteRequest } from '../../../api';
import { getNextDialogIndex, removeFromArray } from '../../../shared/utils';
import { removeFromArray } from '../../../shared/utils';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { useAvatarStore, useFavoriteStore, useGalleryStore, useUserStore } from '../../../stores';
const emit = defineEmits(['update:avatarImportDialogInput']);

View File

@@ -130,7 +130,8 @@
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
import { favoriteRequest, userRequest } from '../../../api';
import { getNextDialogIndex, removeFromArray, userImage, userImageFull } from '../../../shared/utils';
import { removeFromArray, userImage, userImageFull } from '../../../shared/utils';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { useFavoriteStore, useGalleryStore, useUserStore } from '../../../stores';
const { t } = useI18n();

View File

@@ -179,7 +179,8 @@
import { useI18n } from 'vue-i18n';
import { storeToRefs } from 'pinia';
import { favoriteRequest, worldRequest } from '../../../api';
import { getNextDialogIndex, removeFromArray } from '../../../shared/utils';
import { removeFromArray } from '../../../shared/utils';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { useFavoriteStore, useGalleryStore, useUserStore, useWorldStore } from '../../../stores';
const { showUserDialog } = useUserStore();

View File

@@ -1207,37 +1207,40 @@
<template v-if="nowPlaying.playing">
<span style="float: right; padding-left: 10px">{{ nowPlaying.remainingText }}</span>
<MarqueeText>{{ nowPlaying.name }}</MarqueeText>
<div class="np-progress-bar" style="margin-left: 5px" :style="{ width: nowPlaying.percentage + '%' }"></div>
<div
class="np-progress-bar"
style="margin-left: 5px"
:style="{ width: nowPlaying.percentage + '%' }"></div>
</template>
<div style="float: right"
>
<div style="float: right">
<span v-if="!config?.minimalFeed" style="display: inline-block">{{ t('vr.status.timer') }}</span>
<span v-if="lastLocationTimer" style="display: inline-block">{{ lastLocationTimer }}</span>
<span v-if="lastLocationTimer && (onlineForTimer || pcUptime)" style="display: inline-block"> | </span>
<span v-if="onlineForTimer" style="display: inline-block; margin-left: 5px">{{ onlineForTimer }}</span>
<span v-if="lastLocationTimer && (onlineForTimer || pcUptime)" style="display: inline-block">
|
</span>
<span v-if="onlineForTimer" style="display: inline-block; margin-left: 5px">{{
onlineForTimer
}}</span>
<span v-if="pcUptime && onlineForTimer" style="display: inline-block; margin-left: 5px"> | </span>
<span v-if="pcUptime" style="display: inline-block; margin-left: 5px">{{ pcUptime }}</span>
</div>
<template v-if="lastLocation.playerList.length">
<span v-if="!config?.minimalFeed" style="display: inline-block"
>{{ t('vr.status.players') }}</span
>
<span style="display: inline-block"
>{{ lastLocation.playerList.length }}</span>
<span v-if="!config?.minimalFeed" style="display: inline-block">{{ t('vr.status.players') }}</span>
<span style="display: inline-block">{{ lastLocation.playerList.length }}</span>
</template>
<span v-if="lastLocation.friendList.length" style="display: inline-block; font-weight: bold; margin-left: 5px">({{lastLocation.friendList.length}})</span>
<span
v-if="lastLocation.friendList.length"
style="display: inline-block; font-weight: bold; margin-left: 5px"
>({{ lastLocation.friendList.length }})</span
>
<!-- Bottom row -->
<br />
<span style="position: absolute; right: 10px">{{ currentTime }}</span>
<span v-if="config && cpuUsageEnabled" style="display: inline-block; margin-right: 5px"
>{{ t('vr.status.cpu') }} {{ cpuUsage }}%</span
>
<span style="display: inline-block"
>{{ t('vr.status.online') }} {{ onlineFriendCount }}</span
>
<span style="display: inline-block; margin-left: 5px"
>{{ customInfo }}</span
>
<span style="display: inline-block">{{ t('vr.status.online') }} {{ onlineFriendCount }}</span>
<span style="display: inline-block; margin-left: 5px">{{ customInfo }}</span>
</div>
</template>
<!-- HMD Overlay -->
@@ -1368,10 +1371,6 @@
<script setup>
import './vr.scss';
import '@fontsource/noto-sans-kr';
import '@fontsource/noto-sans-jp';
import '@fontsource/noto-sans-sc';
import '@fontsource/noto-sans-tc';
import { onMounted, reactive, toRefs, nextTick } from 'vue';
import Noty from 'noty';
import * as workerTimers from 'worker-timers';
@@ -1381,6 +1380,7 @@
import { escapeTag, escapeTagRecursive } from '../shared/utils/base/string';
import { removeFromArray } from '../shared/utils/base/array';
import { timeToText } from '../shared/utils/base/format';
import { changeHtmlLangAttribute } from '../shared/utils/base/ui';
import { useI18n } from 'vue-i18n';
@@ -1974,7 +1974,8 @@
}
if (appLanguage !== vrState.appLanguage) {
vrState.appLanguage = appLanguage;
// @ts-ignore
changeHtmlLangAttribute(vrState.appLanguage);
//@ts-ignore
i18n.locale = vrState.appLanguage;
}
}
@@ -2020,4 +2021,4 @@
.ml-5 {
margin-left: 5px;
}
</style>
</style>

View File

@@ -29,6 +29,38 @@ body {
margin: 0;
}
html[lang='ja'] body,
html[lang='ja'] * {
font-family:
'ellipsis-font', 'Noto Sans JP', 'Noto Sans KR', 'Noto Sans TC',
'Noto Sans SC', 'Meiryo UI', 'Malgun Gothic', 'Segoe UI', system-ui,
sans-serif;
}
html[lang='ko'] body,
html[lang='ko'] * {
font-family:
'ellipsis-font', 'Noto Sans KR', 'Noto Sans JP', 'Noto Sans TC',
'Noto Sans SC', 'Meiryo UI', 'Malgun Gothic', 'Segoe UI', system-ui,
sans-serif;
}
html[lang='zh-CN'] body,
html[lang='zh-CN'] * {
font-family:
'ellipsis-font', 'Noto Sans SC', 'Noto Sans TC', 'Noto Sans JP',
'Noto Sans KR', 'Meiryo UI', 'Malgun Gothic', 'Segoe UI', system-ui,
sans-serif;
}
html[lang='zh-TW'] body,
html[lang='zh-TW'] * {
font-family:
'ellipsis-font', 'Noto Sans TC', 'Noto Sans SC', 'Noto Sans JP',
'Noto Sans KR', 'Meiryo UI', 'Malgun Gothic', 'Segoe UI', system-ui,
sans-serif;
}
.noty_body {
display: block;
}