From e21a53bdcf279b839fc4bd837086c6a1ff2ce5c8 Mon Sep 17 00:00:00 2001 From: kamiya10 <58339640+kamiya10@users.noreply.github.com> Date: Sat, 24 Dec 2022 22:30:31 +0800 Subject: [PATCH] feat: Localization --- html/package-lock.json | 13 + html/package.json | 3 + html/src/app.js | 10 + html/src/index.pug | 1318 ++++++++++----------- html/src/localization/localizedStrings.js | 5 + html/src/localization/strings/en.json | 800 +++++++++++++ html/src/localization/strings/zh_TW.json | 802 +++++++++++++ 7 files changed, 2292 insertions(+), 659 deletions(-) create mode 100644 html/src/localization/localizedStrings.js create mode 100644 html/src/localization/strings/en.json create mode 100644 html/src/localization/strings/zh_TW.json diff --git a/html/package-lock.json b/html/package-lock.json index 217e5a29..1f06e9c2 100644 --- a/html/package-lock.json +++ b/html/package-lock.json @@ -5,6 +5,9 @@ "packages": { "": { "license": "MIT", + "dependencies": { + "vue-i18n": "^8.28.2" + }, "devDependencies": { "@fontsource/noto-sans-jp": "^4.5.12", "@fontsource/noto-sans-kr": "^4.5.12", @@ -3827,6 +3830,11 @@ "npm": ">= 3.0.0" } }, + "node_modules/vue-i18n": { + "version": "8.28.2", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.28.2.tgz", + "integrity": "sha512-C5GZjs1tYlAqjwymaaCPDjCyGo10ajUphiwA922jKt9n7KPpqR7oM1PCwYzhB/E7+nT3wfdG3oRre5raIT1rKA==" + }, "node_modules/vue-lazyload": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/vue-lazyload/-/vue-lazyload-1.3.4.tgz", @@ -6948,6 +6956,11 @@ "vue": "^2.5.16" } }, + "vue-i18n": { + "version": "8.28.2", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.28.2.tgz", + "integrity": "sha512-C5GZjs1tYlAqjwymaaCPDjCyGo10ajUphiwA922jKt9n7KPpqR7oM1PCwYzhB/E7+nT3wfdG3oRre5raIT1rKA==" + }, "vue-lazyload": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/vue-lazyload/-/vue-lazyload-1.3.4.tgz", diff --git a/html/package.json b/html/package.json index 482a7123..9bacd175 100644 --- a/html/package.json +++ b/html/package.json @@ -49,5 +49,8 @@ "webpack": "^5.75.0", "webpack-cli": "^5.0.0", "worker-timers": "^7.0.60" + }, + "dependencies": { + "vue-i18n": "^8.28.2" } } diff --git a/html/src/app.js b/html/src/app.js index 5d79885e..af7abe5a 100644 --- a/html/src/app.js +++ b/html/src/app.js @@ -9,6 +9,7 @@ import '@fontsource/noto-sans-jp'; import Noty from 'noty'; import Vue from 'vue'; import VueLazyload from 'vue-lazyload'; +import VueI18n from 'vue-i18n' import {DataTables} from 'vue-data-tables'; import ElementUI from 'element-ui'; import locale from 'element-ui/lib/locale/lang/en'; @@ -21,6 +22,7 @@ import webApiService from './service/webapi.js'; import gameLogService from './service/gamelog.js'; import security from './security.js'; import database from './repository/database.js'; +import * as localizedStrings from './localization/localizedStrings.js'; speechSynthesis.getVoices(); @@ -205,6 +207,13 @@ speechSynthesis.getVoices(); Vue.use(DataTables); + Vue.use(VueI18n); + + var i18n = new VueI18n({ + locale: 'en', + messages: localizedStrings, + }) + var $appDarkStyle = document.createElement('link'); $appDarkStyle.disabled = true; $appDarkStyle.rel = 'stylesheet'; @@ -4625,6 +4634,7 @@ speechSynthesis.getVoices(); exportFriendsListDialog: false, exportFriendsListContent: '' }, + i18n, computed: {}, methods: {}, watch: {}, diff --git a/html/src/index.pug b/html/src/index.pug index 2668560e..8168f289 100644 --- a/html/src/index.pug +++ b/html/src/index.pug @@ -18,7 +18,7 @@ html el-button(type="default" @click="showVRCXUpdateDialog" size="mini" icon="el-icon-download" circle) div(style="width:300px;margin:auto") div(style="margin:15px" v-if="Object.keys(loginForm.savedCredentials).length !== 0") - h2(style="font-weight:bold;text-align:center;margin:0") Saved Accounts + h2(style="font-weight:bold;text-align:center;margin:0") {{ $t("view.login.savedAccounts") }} .x-friend-list(style="margin-top:10px") .x-friend-item(v-for="user in loginForm.savedCredentials" :key="user.user.id") .x-friend-item(@click="relogin(user)" style="width:202px;padding:0") @@ -30,27 +30,27 @@ html span.extra(v-text="user.loginParmas.endpoint") el-button(type="default" @click="deleteSavedLogin(user.user.username)" size="mini" icon="el-icon-delete" circle) div(style="margin:15px") - h2(style="font-weight:bold;text-align:center;margin:0") Login + h2(style="font-weight:bold;text-align:center;margin:0") {{ $t("view.login.login") }} el-form(ref="loginForm" :model="loginForm" :rules="loginForm.rules" @submit.native.prevent="login()") - el-form-item(label="Username or Email" prop="username" required) - el-input(v-model="loginForm.username" name="username" placeholder="Username or Email" clearable) - el-form-item(label="Password" prop="password" required style="margin-top:10px") - el-input(type="password" v-model="loginForm.password" name="password" placeholder="Password" clearable show-password) - el-checkbox(v-model="loginForm.saveCredentials" style="margin-top:15px") Save Credentials - el-checkbox(v-model="enableCustomEndpoint" @change="toggleCustomEndpoint" style="margin-top:10px") Dev Endpoint - el-form-item(v-if="enableCustomEndpoint" label="Endpont" prop="endpoint" style="margin-top:10px") + el-form-item(:label="$t('view.login.field.username')" prop="username" required) + el-input(v-model="loginForm.username" name="username" :placeholder="$t('view.login.field.username')" clearable) + el-form-item(:label="$t('view.login.field.password')" prop="password" required style="margin-top:10px") + el-input(type="password" v-model="loginForm.password" name="password" :placeholder="$t('view.login.field.password')" clearable show-password) + el-checkbox(v-model="loginForm.saveCredentials" style="margin-top:15px") {{ $t("view.login.field.saveCredentials") }} + el-checkbox(v-model="enableCustomEndpoint" @change="toggleCustomEndpoint" style="margin-top:10px") {{ $t("view.login.field.devEndpoint") }} + el-form-item(v-if="enableCustomEndpoint" :label="$t('view.login.field.endpoint')" prop="endpoint" style="margin-top:10px") el-input(v-model="loginForm.endpoint" name="endpoint" :placeholder="API.endpointDomainVrchat" clearable) - el-form-item(v-if="enableCustomEndpoint" label="WebSocket" prop="endpoint" style="margin-top:10px") + el-form-item(v-if="enableCustomEndpoint" :label="$t('view.login.field.websocket')" prop="endpoint" style="margin-top:10px") el-input(v-model="loginForm.websocket" name="websocket" :placeholder="API.websocketDomainVrchat" clearable) el-form-item(style="margin-top:15px") - el-button(native-type="submit" type="primary" :loading="loginForm.loading" style="width:100%") Login - el-button(type="primary" @click="openExternalLink('https://vrchat.com/register')" :loading="loginForm.loading" style="width:100%") Register + el-button(native-type="submit" type="primary" :loading="loginForm.loading" style="width:100%") {{ $t("view.login.login") }} + el-button(type="primary" @click="openExternalLink('https://vrchat.com/register')" :loading="loginForm.loading" style="width:100%") {{ $t("view.login.register") }} div(style="text-align:center;font-size:12px") - p #[a(@click="openExternalLink('https://vrchat.com/home/password')") Forgot password?] + p #[a(@click="openExternalLink('https://vrchat.com/home/password')") {{ $t("view.login.forgotPassword") }}] p © 2019-2022 #[a(@click="openExternalLink('https://github.com/pypy-vrc')") pypy] (mina#5656) & #[a(@click="openExternalLink('https://github.com/Natsumi-sama')") Natsumi] - p VRCX is an assistant application for provide information about manage friendship. this application uses unofficial VRChat API (VRCSDK). - p VRCX isn't endorsed by VRChat and doesn't reflect the views or opinions of VRChat or anyone officially involved in producing or managing VRChat. VRChat is trademark of VRChat Inc. VRChat © VRChat Inc. - p pypy or Natsumi aren't responsible for any problems caused by VRCX. Use at your own risk! + p {{ $t("view.settings.general.legal_notice.info") }} + p {{ $t("view.settings.general.legal_notice.disclaimer1") }} + p {{ $t("view.settings.general.legal_notice.disclaimer2") }} //- menu .x-menu-container @@ -64,17 +64,17 @@ html i(class=icon) template(#title) span= name - +menuitem('feed', 'Feed', 'el-icon-news') - +menuitem('gameLog', 'Game Log', 'el-icon-s-data') - +menuitem('playerList', 'Player List', 'el-icon-tickets') - +menuitem('search', 'Search', 'el-icon-search') - +menuitem('favorite', 'Favorites', 'el-icon-star-off') - +menuitem('friendLog', 'Friend Log', 'el-icon-notebook-2') - +menuitem('moderation', 'Moderation', 'el-icon-finished') - +menuitem('notification', 'Notification', 'el-icon-bell') - +menuitem('friendsList', 'Friends List', 'el-icon-s-management') - +menuitem('profile', 'Profile', 'el-icon-user') - +menuitem('settings', 'Settings', 'el-icon-s-tools') + +menuitem('feed', "{{ $t('nav_tooltip.feed') }}", 'el-icon-news') + +menuitem('gameLog', "{{ $t('nav_tooltip.game_log') }}", 'el-icon-s-data') + +menuitem('playerList', "{{ $t('nav_tooltip.player_list') }}", 'el-icon-tickets') + +menuitem('search', "{{ $t('nav_tooltip.search') }}", 'el-icon-search') + +menuitem('favorite', "{{ $t('nav_tooltip.favorites') }}", 'el-icon-star-off') + +menuitem('friendLog', "{{ $t('nav_tooltip.friend_log') }}", 'el-icon-notebook-2') + +menuitem('moderation', "{{ $t('nav_tooltip.moderation') }}", 'el-icon-finished') + +menuitem('notification', "{{ $t('nav_tooltip.notification') }}", 'el-icon-bell') + +menuitem('friendsList', "{{ $t('nav_tooltip.friend_list') }}", 'el-icon-s-management') + +menuitem('profile', "{{ $t('nav_tooltip.profile') }}", 'el-icon-user') + +menuitem('settings', "{{ $t('nav_tooltip.settings') }}", 'el-icon-s-tools') //- playerList .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'playerList'") @@ -134,17 +134,17 @@ html el-tabs(type="card") el-tab-pane(label="Current") data-tables(v-bind="photonEventTable" style="margin-bottom:10px") - el-table-column(label="Date" prop="created_at" width="120") + el-table-column(:label="$t('table.playerList.date')" prop="created_at" width="120") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created_at | formatDate('long') }} span {{ scope.row.created_at | formatDate('short') }} - el-table-column(label="User" prop="photonId" width="160") + el-table-column(:label="$t('table.playerList.user')" prop="photonId" width="160") template(v-once #default="scope") span.x-link(v-text="scope.row.displayName" @click="showUserFromPhotonId(scope.row.photonId)" style="padding-right:10px") - el-table-column(label="Type" prop="type" width="140") - el-table-column(label="Details" prop="text") + el-table-column(:label="$t('table.playerList.type')" prop="type" width="140") + el-table-column(:label="$t('table.playerList.detail')" prop="text") template(v-once #default="scope") template(v-if="scope.row.type === 'ChangeAvatar'") span.x-link(v-text="scope.row.avatar.name" @click="showAvatarDialog(scope.row.avatar.id)") @@ -188,7 +188,7 @@ html span(v-else v-text="scope.row.text") el-tab-pane(label="Previous") data-tables(v-bind="photonEventTablePrevious" style="margin-bottom:10px") - el-table-column(label="Date" prop="created_at" width="120") + el-table-column(:label="$t('table.playerList.date')" prop="created_at" width="120") template(v-once #default="scope") el-tooltip(placement="right") template(#content) @@ -242,16 +242,16 @@ html span(v-else v-text="scope.row.text") div.current-instance-table data-tables(v-bind="currentInstanceUserList" @row-click="selectCurrentInstanceRow" style="margin-top:10px;cursor:pointer") - el-table-column(label="Avatar" width="70" prop="photo") + el-table-column(:label="$t('table.playerList.avatar')" width="70" prop="photo") template(v-once #default="scope") template(v-if="userImage(scope.row.ref)") el-popover(placement="right" height="500px" trigger="hover") img.friends-list-avatar(slot="reference" v-lazy="userImage(scope.row.ref)") img.friends-list-avatar(v-lazy="userImageFull(scope.row.ref)" style="height:500px;cursor:pointer" @click="downloadAndSaveImage(userImageFull(scope.row.ref))") - el-table-column(label="Timer" width="90" prop="timer" sortable) + el-table-column(:label="$t('table.playerList.timer')" width="90" prop="timer" sortable) template(v-once #default="scope") timer(:epoch="scope.row.timer") - el-table-column(v-if="photonLoggingEnabled" label="Photon Id" width="110" prop="photonId" sortable) + el-table-column(v-if="photonLoggingEnabled" :label="$t('table.playerList.photonId')" width="110" prop="photonId" sortable) template(v-once #default="scope") template(v-if="chatboxUserBlacklist.has(scope.row.ref.id)") el-tooltip(placement="left" content="Unblock chatbox messages") @@ -260,7 +260,7 @@ html el-tooltip(placement="left" content="Block chatbox messages") el-button(type="text" icon="el-icon-microphone" size="mini" style="margin-right:5px" @click.stop="addChatboxUserBlacklist(scope.row.ref)") span(v-text="scope.row.photonId") - el-table-column(label="Icons" prop="isMaster" width="100") + el-table-column(:label="$t('table.playerList.icon')" prop="isMaster" width="100") template(v-once #default="scope") el-tooltip(v-if="scope.row.isMaster" placement="left" content="Instance Master") span 👑 @@ -268,7 +268,7 @@ html span 💚 el-tooltip(v-if="scope.row.timeoutTime" placement="left" content="Timeout") span(style="color:red") 🔴{{ scope.row.timeoutTime }}s - el-table-column(label="Platform" prop="inVRMode" width="80") + el-table-column(:label="$t('table.playerList.platform')" prop="inVRMode" width="80") template(v-once #default="scope") template(v-if="scope.row.ref.last_platform") span(v-if="scope.row.ref.last_platform === 'standalonewindows'" style="color:#409eff") PC @@ -277,11 +277,11 @@ html template(v-if="scope.row.inVRMode !== null") span(v-if="scope.row.inVRMode") VR span(v-else) D - el-table-column(label="Display Name" min-width="140" prop="ref.displayName") + el-table-column(:label="$t('table.playerList.displayName')" min-width="140" prop="ref.displayName") template(v-once #default="scope") span(v-if="randomUserColours" v-text="scope.row.ref.displayName" :style="{'color':scope.row.ref.$userColour}") span(v-else v-text="scope.row.ref.displayName") - el-table-column(label="Status" min-width="180" prop="ref.status") + el-table-column(:label="$t('table.playerList.status')" min-width="180" prop="ref.status") template(v-once #default="scope") template(v-if="scope.row.ref.status") i.x-user-status(:class="statusClass(scope.row.ref.status)") @@ -290,16 +290,16 @@ html //- el-table-column(label="Group" min-width="180" prop="groupOnNameplate" sortable) //- template(v-once #default="scope") //- span(v-text="scope.row.groupOnNameplate") - el-table-column(label="Rank" width="110" prop="$trustSortNum" sortable="custom") + el-table-column(:label="$t('table.playerList.rank')" width="110" prop="$trustSortNum" sortable="custom") template(v-once #default="scope") span.name(v-text="scope.row.ref.$trustLevel" :class="scope.row.ref.$trustClass") - el-table-column(label="Language" width="100" prop="ref.$languages") + el-table-column(:label="$t('table.playerList.language')" width="100" prop="ref.$languages") template(v-once #default="scope") el-tooltip(v-for="item in scope.row.ref.$languages" :key="item.key" placement="top") template(#content) span {{ item.value }} ({{ item.key }}) span.flags(:class="languageClass(item.key)" style="display:inline-block;margin-left:5px") - el-table-column(label="Bio Links" width="100" prop="ref.bioLinks") + el-table-column(:label="$t('table.playerList.bioLink')" width="100" prop="ref.bioLinks") template(v-once #default="scope") el-tooltip(v-if="link" v-for="(link, index) in scope.row.ref.bioLinks" :key="index") template(#content) @@ -312,11 +312,11 @@ html template(#tool) div(style="margin:0 0 10px;display:flex;align-items:center") div(style="flex:none;margin-right:10px") - el-tooltip(placement="bottom" content="Filter VIP only" :disabled="hideTooltips") + el-tooltip(placement="bottom" :content="$t('view.feed.favorites_only_tooltip')" :disabled="hideTooltips") el-switch(v-model="feedTable.vip" @change="feedTableLookup" active-color="#13ce66") - el-select(v-model="feedTable.filter" @change="feedTableLookup" multiple clearable collapse-tags style="flex:1" placeholder="Filter") + el-select(v-model="feedTable.filter" @change="feedTableLookup" multiple clearable collapse-tags style="flex:1" :placeholder="$t('view.feed.filter_placeholder')") el-option(v-once v-for="type in ['GPS', 'Online', 'Offline', 'Status', 'Avatar', 'Bio']" :key="type" :label="type" :value="type") - el-input(v-model="feedTable.search" placeholder="Search" @keyup.native.13="feedTableLookup" @change="feedTableLookup" clearable style="flex:none;width:150px;margin:0 10px") + el-input(v-model="feedTable.search" :placeholder="$t('view.feed.search_placeholder')" @keyup.native.13="feedTableLookup" @change="feedTableLookup" clearable style="flex:none;width:150px;margin:0 10px") //- el-tooltip(placement="bottom" content="Clear feed" :disabled="hideTooltips") //- el-button(type="default" @click="clearFeed()" icon="el-icon-delete" circle style="flex:none") el-table-column(type="expand" width="20") @@ -371,17 +371,17 @@ html span i.el-icon-right pre(v-text="scope.row.bio" style="font-family:inherit;font-size:12px;white-space:pre-wrap;margin:0 0.5em 0 0") - el-table-column(label="Date" prop="created_at" sortable="custom" width="120") + el-table-column(:label="$t('table.feed.date')" prop="created_at" sortable="custom" width="120") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created_at | formatDate('long') }} span {{ scope.row.created_at | formatDate('short') }} - el-table-column(label="Type" prop="type" width="70") - el-table-column(label="User" prop="displayName" width="180") + el-table-column(:label="$t('table.feed.type')" prop="type" width="70") + el-table-column(:label="$t('table.feed.user')" prop="displayName" width="180") template(v-once #default="scope") span.x-link(v-text="scope.row.displayName" @click="showUserDialog(scope.row.userId)") - el-table-column(label="Detail") + el-table-column(:label="$t('table.feed.detail')") template(v-once #default="scope") template(v-if="scope.row.type === 'GPS'") location(v-if="scope.row.location" :location="scope.row.location" :hint="scope.row.worldName" :grouphint="scope.row.groupName") @@ -428,32 +428,32 @@ html data-tables(v-bind="gameLogTable" v-loading="gameLogTable.loading") template(#tool) div(style="margin:0 0 10px;display:flex;align-items:center") - el-select(v-model="gameLogTable.filter" @change="gameLogTableLookup" multiple clearable collapse-tags style="flex:1" placeholder="Filter") + el-select(v-model="gameLogTable.filter" @change="gameLogTableLookup" multiple clearable collapse-tags style="flex:1" :placeholder="$t('view.game_log.filter_placeholder')") el-option(v-once v-for="type in ['Location', 'OnPlayerJoined', 'OnPlayerLeft', 'PortalSpawn', 'Event', 'VideoPlay']" :key="type" :label="type" :value="type") - el-input(v-model="gameLogTable.search" placeholder="Search" @keyup.native.13="gameLogTableLookup" @change="gameLogTableLookup" clearable style="flex:none;width:150px;margin:0 10px") + el-input(v-model="gameLogTable.search" :placeholder="$t('view.game_log.search_placeholder')" @keyup.native.13="gameLogTableLookup" @change="gameLogTableLookup" clearable style="flex:none;width:150px;margin:0 10px") //- el-tooltip(placement="bottom" content="Reload game log" :disabled="hideTooltips") //- el-button(type="default" @click="resetGameLog" icon="el-icon-refresh" circle style="flex:none") - el-table-column(label="Date" prop="created_at" sortable="custom" width="120") + el-table-column(:label="$t('table.gameLog.date')" prop="created_at" sortable="custom" width="120") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created_at | formatDate('long') }} span {{ scope.row.created_at | formatDate('short') }} - el-table-column(label="Type" prop="type" width="120") + el-table-column(:label="$t('table.gameLog.type')" prop="type" width="120") template(v-once #default="scope") span.x-link(v-if="scope.row.location && scope.row.type !== 'Location'" v-text="scope.row.type" @click="showWorldDialog(scope.row.location)") span(v-else v-text="scope.row.type") - el-table-column(label="User" prop="displayName" width="180") + el-table-column(:label="$t('table.gameLog.user')" prop="displayName" width="180") template(v-once #default="scope") span.x-link(v-if="scope.row.displayName" v-text="scope.row.displayName" @click="lookupUser(scope.row)" style="padding-right:10px") - el-table-column(label="Detail" prop="data") + el-table-column(:label="$t('table.gameLog.detail')" prop="data") template(v-once #default="scope") location(v-if="scope.row.type === 'Location'" :location="scope.row.location" :hint="scope.row.worldName" :grouphint="scope.row.groupName") location(v-else-if="scope.row.type === 'PortalSpawn'" :location="scope.row.instanceId" :hint="scope.row.worldName" :grouphint="scope.row.groupName") template(v-else-if="scope.row.type === 'Event'") span(v-text="scope.row.data") template(v-else-if="scope.row.type === 'VideoPlay'") - span(v-if="scope.row.videoId") {{ scope.row.videoId }}: + span(v-if="scope.row.videoId") {{ scope.row.videoId }}: span(v-if="scope.row.videoId === 'LSMedia'" v-text="scope.row.videoName") span.x-link(v-else-if="scope.row.videoName" @click="openExternalLink(scope.row.videoUrl)" v-text="scope.row.videoName") span.x-link(v-else @click="openExternalLink(scope.row.videoUrl)" v-text="scope.row.videoUrl") @@ -463,11 +463,11 @@ html //- search .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'search'") div(style="margin:0 0 10px;display:flex;align-items:center") - el-input(v-model="searchText" placeholder="Search" @keyup.native.13="search()" style="flex:1") - el-tooltip(placement="bottom" content="Clear search results" :disabled="hideTooltips") + el-input(v-model="searchText" :placeholder="$t('view.search.search_placeholder')" @keyup.native.13="search()" style="flex:1") + el-tooltip(placement="bottom" :content="$t('view.search.clear_results_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="clearSearch()" icon="el-icon-delete" circle style="flex:none;margin-left:10px") el-tabs(ref="searchTab" type="card" style="margin-top:15px") - el-tab-pane(label="User" v-loading="isSearchUserLoading" style="min-height:60px") + el-tab-pane(:label="$t('view.search.user.header')" v-loading="isSearchUserLoading" style="min-height:60px") .x-friend-list .x-friend-item(v-for="user in searchUserResults" :key="user.id" @click="showUserDialog(user.id)") template(v-once) @@ -478,14 +478,14 @@ html span.extra(v-if="randomUserColours" v-text="user.$trustLevel" :class="user.$trustClass") span.extra(v-else v-text="user.$trustLevel" :style="{'color':user.$userColour}") el-button-group(style="margin-top:15px") - el-button(v-if="searchUserParams.offset" @click="moreSearchUser(-1)" icon="el-icon-back" size="small") Prev - el-button(v-if="searchUserResults.length" @click="moreSearchUser(1)" icon="el-icon-right" size="small") Next - el-tab-pane(label="World" v-loading="isSearchWorldLoading" style="min-height:60px") + el-button(v-if="searchUserParams.offset" @click="moreSearchUser(-1)" icon="el-icon-back" size="small") {{ $t('view.search.prev_page') }} + el-button(v-if="searchUserResults.length" @click="moreSearchUser(1)" icon="el-icon-right" size="small") {{ $t('view.search.next_page') }} + el-tab-pane(:label="$t('view.search.world.header')" v-loading="isSearchWorldLoading" style="min-height:60px") el-dropdown(@command="(row) => searchWorld(row)" size="small" trigger="click" style="margin-bottom:15px") - el-button(size="small") Search by Category #[i.el-icon-arrow-down.el-icon--right] + el-button(size="small") {{ $t('view.search.world.category') }} #[i.el-icon-arrow-down.el-icon--right] el-dropdown-menu(#default="dropdown") el-dropdown-item(v-for="row in API.cachedConfig.dynamicWorldRows" :key="row.index" v-text="row.name" :command="row") - el-checkbox(v-model="searchWorldLabs" style="margin-left:10px") Include community labs + el-checkbox(v-model="searchWorldLabs" style="margin-left:10px") {{ $t('view.search.world.community_lab') }} .x-friend-list .x-friend-item(v-for="world in searchWorldResults" :key="world.id" @click="showWorldDialog(world.id)") template(v-once) @@ -496,28 +496,28 @@ html span.extra(v-if="world.occupants") {{ world.authorName }} ({{ world.occupants }}) span.extra(v-else v-text="world.authorName") el-button-group(style="margin-top:15px") - el-button(v-if="searchWorldParams.offset" @click="moreSearchWorld(-1)" icon="el-icon-back" size="small") Prev - el-button(v-if="searchWorldResults.length >= 10" @click="moreSearchWorld(1)" icon="el-icon-right" size="small") Next - el-tab-pane(label="Avatar" v-loading="isSearchAvatarLoading" style="min-height:60px") + el-button(v-if="searchWorldParams.offset" @click="moreSearchWorld(-1)" icon="el-icon-back" size="small") {{ $t('view.search.prev_page') }} + el-button(v-if="searchWorldResults.length >= 10" @click="moreSearchWorld(1)" icon="el-icon-right" size="small") {{ $t('view.search.next_page') }} + el-tab-pane(:label="$t('view.search.avatar.header')" v-loading="isSearchAvatarLoading" style="min-height:60px") el-dropdown(v-if="avatarRemoteDatabaseProviderList.length > 1" trigger="click" @click.native.stop size="mini" style="margin-right:5px") - el-button(size="small") Search Provider #[i.el-icon-arrow-down.el-icon--right] + el-button(size="small") {{ $t('view.search.avatar.search_provider') }} #[i.el-icon-arrow-down.el-icon--right] el-dropdown-menu(#default="dropdown") el-dropdown-item(v-for="provider in avatarRemoteDatabaseProviderList" :key="provider" @click.native="setAvatarProvider(provider)") #[i.el-icon-check.el-icon--left(v-if="provider === avatarRemoteDatabaseProvider")] {{ provider }} - el-tooltip(placement="bottom" content="Refresh own avatars" :disabled="hideTooltips") + el-tooltip(placement="bottom" :content="$t('view.search.avatar.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" :loading="userDialog.isAvatarsLoading" @click="refreshUserDialogAvatars()" size="mini" icon="el-icon-refresh" circle) - span(style="font-size:14px;margin-left:5px;margin-right:5px") Results {{ searchAvatarResults.length }} + span(style="font-size:14px;margin-left:5px;margin-right:5px") {{ $t("view.search.avatar.result_count", { count: searchAvatarResults.length }) }} el-radio-group(v-model="searchAvatarFilter" size="mini" style="margin:5px;display:block" @change="searchAvatar") - el-radio(label="all") all - el-radio(label="public") public - el-radio(label="private") private + el-radio(label="all") {{ $t('view.search.avatar.all') }} + el-radio(label="public") {{ $t('view.search.avatar.public') }} + el-radio(label="private") {{ $t('view.search.avatar.private') }} el-radio-group(v-model="searchAvatarFilterRemote" size="mini" style="margin:5px;display:block" @change="searchAvatar") - el-radio(label="all") all - el-radio(label="local") local - el-radio(label="remote" :disabled="!avatarRemoteDatabase") remote + el-radio(label="all") {{ $t('view.search.avatar.all') }} + el-radio(label="local") {{ $t('view.search.avatar.local') }} + el-radio(label="remote" :disabled="!avatarRemoteDatabase") {{ $t('view.search.avatar.remote') }} el-radio-group(:disabled="searchAvatarFilterRemote !== 'local'" v-model="searchAvatarSort" size="mini" style="margin:5px;display:block" @change="searchAvatar") - el-radio(label="name") by name - el-radio(label="update") by update - el-radio(label="created") by created + el-radio(label="name") {{ $t('view.search.avatar.sort_name') }} + el-radio(label="update") {{ $t('view.search.avatar.sort_update') }} + el-radio(label="created") {{ $t('view.search.avatar.sort_created') }} .x-friend-list(style="margin-top:20px") .x-friend-item(v-for="avatar in searchAvatarPage" :key="avatar.id" @click="showAvatarDialog(avatar.id)") template(v-once) @@ -531,25 +531,25 @@ html span.extra(v-text="avatar.releaseStatus" v-else) span.extra(v-text="avatar.authorName") el-button-group(style="margin-top:15px") - el-button(v-if="searchAvatarPageNum" @click="moreSearchAvatar(-1)" icon="el-icon-back" size="small") Prev - el-button(v-if="searchAvatarResults.length > 10 && (searchAvatarPageNum + 1) * 10 < searchAvatarResults.length" @click="moreSearchAvatar(1)" icon="el-icon-right" size="small") Next + el-button(v-if="searchAvatarPageNum" @click="moreSearchAvatar(-1)" icon="el-icon-back" size="small") {{ $t('view.search.prev_page') }} + el-button(v-if="searchAvatarResults.length > 10 && (searchAvatarPageNum + 1) * 10 < searchAvatarResults.length" @click="moreSearchAvatar(1)" icon="el-icon-right" size="small") {{ $t('view.search.next_page') }} //- favorite .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'favorite'") - el-tooltip(placement="bottom" content="Refresh all favorites" :disabled="hideTooltips") + el-tooltip(placement="bottom" :content="$t('view.favorite.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" :loading="API.isFavoriteLoading" @click="API.refreshFavorites(); getLocalWorldFavorites()" size="small" icon="el-icon-refresh" circle style="position:relative;float:right;z-index:1") el-tabs(ref="favoriteTabRef" type="card" v-loading="API.isFavoriteLoading") - el-tab-pane(label="Friends") + el-tab-pane(:label="$t('view.favorite.friends.header')") el-collapse(v-if="$refs.menu && $refs.menu.activeIndex === 'favorite' && $refs.favoriteTabRef && $refs.favoriteTabRef.currentName === '0'" style="border:0") - el-button(size="small" @click="showFriendExportDialog") Export - el-button(size="small" @click="showFriendImportDialog") Import + el-button(size="small" @click="showFriendExportDialog") {{ $t('view.favorite.export') }} + el-button(size="small" @click="showFriendImportDialog") {{ $t('view.favorite.import') }} el-collapse-item(v-for="group in API.favoriteFriendGroups" :key="group.name") template(slot="title") span(v-text="group.displayName" style="font-weight:bold;font-size:14px;margin-left:10px") span(style="color:#909399;font-size:12px;margin-left:10px") {{ group.count }}/{{ group.capacity }} - el-tooltip(placement="top" content="Rename" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.favorite.rename_tooltip')" :disabled="hideTooltips") el-button(@click.stop="changeFavoriteGroupName(group)" size="mini" icon="el-icon-edit" circle style="margin-left:10px") - el-tooltip(placement="right" content="Clear" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('view.favorite.clear_tooltip')" :disabled="hideTooltips") el-button(@click.stop="clearFavoriteGroup(group)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") .x-friend-list(v-if="group.count" style="margin-top:10px") div(style="display:inline-block;width:300px;margin-right:15px" v-for="favorite in favoriteFriends" v-if="favorite.groupKey === group.key" :key="favorite.id" @click="showUserDialog(favorite.id)") @@ -561,35 +561,35 @@ html span.name(v-text="favorite.ref.displayName" :style="{'color':favorite.ref.$userColour}") location.extra(v-if="favorite.ref.location !== 'offline'" :location="favorite.ref.location" :traveling="favorite.ref.travelingToLocation" :link="false") span(v-else v-text="favorite.ref.statusDescription") - el-tooltip(placement="left" content="Move" :disabled="hideTooltips") + el-tooltip(placement="left" :content="$t('view.favorite.move_tooltip')" :disabled="hideTooltips") el-dropdown(trigger="click" @click.native.stop size="mini" style="margin-left:5px") el-button(type="default" icon="el-icon-back" size="mini" circle) el-dropdown-menu(#default="dropdown") template(v-if="groupAPI.name !== group.name" v-for="groupAPI in API.favoriteFriendGroups" :key="groupAPI.name") el-dropdown-item(style="display:block;margin:10px 0" @click.native="moveFavorite(favorite.ref, groupAPI, 'friend')" :disabled="groupAPI.count >= groupAPI.capacity") {{ groupAPI.displayName }} ({{ groupAPI.count }} / {{ groupAPI.capacity }}) - el-tooltip(placement="right" content="Unfavorite" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('view.favorite.unfavorite_tooltip')" :disabled="hideTooltips") el-button(@click.stop="deleteFavorite(favorite.id)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") template(v-else) span(v-text="favorite.name || favorite.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="deleteFavorite(favorite.id)" style="margin-left:5px") - el-tab-pane(label="Worlds") + el-tab-pane(:label="$t('view.favorite.worlds.header')") el-collapse(v-if="$refs.menu && $refs.menu.activeIndex === 'favorite' && $refs.favoriteTabRef && $refs.favoriteTabRef.currentName === '1'" style="border:0") - el-button(size="small" @click="showWorldExportDialog") Export - el-button(size="small" @click="showWorldImportDialog") Import - span(style="display:block;margin-top:20px") VRChat Favorites + el-button(size="small" @click="showWorldExportDialog") {{ $t('view.favorite.export') }} + el-button(size="small" @click="showWorldImportDialog") {{ $t('view.favorite.import') }} + span(style="display:block;margin-top:20px") {{ $t('view.favorite.worlds.vrchat_favorites') }} el-collapse-item(v-for="group in API.favoriteWorldGroups" :key="group.name") template(slot="title") span(v-text="group.displayName" style="font-weight:bold;font-size:14px;margin-left:10px") i.x-user-status(style="margin-left:5px" :class="userFavoriteWorldsStatus(group.visibility)") span(style="color:#909399;font-size:12px;margin-left:10px") {{ group.count }}/{{ group.capacity }} - el-tooltip(placement="top" content="Change visibility" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.favorite.visibility_tooltip')" :disabled="hideTooltips") el-dropdown(trigger="click" @click.native.stop size="mini" style="margin-left:10px") el-button(type="default" icon="el-icon-view" size="mini" circle) el-dropdown-menu(#default="dropdown") el-dropdown-item(v-if="group.visibility !== visibility" v-for="visibility in worldGroupVisibilityOptions" :key="visibility" style="display:block;margin:10px 0" v-text="visibility" @click.native="changeWorldGroupVisibility(group.name, visibility)") - el-tooltip(placement="top" content="Rename" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.favorite.rename_tooltip')" :disabled="hideTooltips") el-button(@click.stop="changeFavoriteGroupName(group)" size="mini" icon="el-icon-edit" circle style="margin-left:5px") - el-tooltip(placement="right" content="Clear" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('view.favorite.clear_tooltip')" :disabled="hideTooltips") el-button(@click.stop="clearFavoriteGroup(group)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") .x-friend-list(v-if="group.count" style="margin-top:10px") div(style="display:inline-block;width:300px;margin-right:15px" v-for="favorite in favoriteWorlds" v-if="favorite.groupKey === group.key" :key="favorite.id" @click="showWorldDialog(favorite.id)") @@ -601,26 +601,26 @@ html span.name(v-text="favorite.ref.name") span.extra(v-if="favorite.ref.occupants") {{ favorite.ref.authorName }} ({{ favorite.ref.occupants }}) span.extra(v-else v-text="favorite.ref.authorName") - el-tooltip(placement="left" content="Move" :disabled="hideTooltips") + el-tooltip(placement="left" :content="$t('view.favorite.move_tooltip')" :disabled="hideTooltips") el-dropdown(trigger="click" @click.native.stop size="mini" style="margin-left:5px") el-button(type="default" icon="el-icon-back" size="mini" circle) el-dropdown-menu(#default="dropdown") template(v-if="groupAPI.name !== group.name" v-for="groupAPI in API.favoriteWorldGroups" :key="groupAPI.name") el-dropdown-item(style="display:block;margin:10px 0" @click.native="moveFavorite(favorite.ref, groupAPI, 'world')" :disabled="groupAPI.count >= groupAPI.capacity") {{ groupAPI.displayName }} ({{ groupAPI.count }} / {{ groupAPI.capacity }}) - el-tooltip(placement="right" content="Unfavorite" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('view.favorite.unfavorite_tooltip')" :disabled="hideTooltips") el-button(@click.stop="deleteFavorite(favorite.id)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") template(v-else) span(v-text="favorite.name || favorite.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="deleteFavorite(favorite.id)" style="margin-left:5px") - span(style="display:block;margin-top:20px") Local Favorites - el-button(size="small" @click="promptNewLocalWorldFavoriteGroup" style="display:block;margin-top:10px") New Group + span(style="display:block;margin-top:20px") {{ $t('view.favorite.worlds.local_favorites') }} + el-button(size="small" @click="promptNewLocalWorldFavoriteGroup" style="display:block;margin-top:10px") {{ $t('view.favorite.worlds.new_group') }} el-collapse-item(v-for="group in localWorldFavoriteGroups" v-if="localWorldFavorites[group]" :key="group") template(slot="title") span(v-text="group" style="font-weight:bold;font-size:14px;margin-left:10px") span(style="color:#909399;font-size:12px;margin-left:10px") {{ getLocalWorldFavoriteGroupLength(group) }} - el-tooltip(placement="top" content="Rename" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.favorite.rename_tooltip')" :disabled="hideTooltips") el-button(@click.stop="promptLocalWorldFavoriteGroupRename(group)" size="mini" icon="el-icon-edit" circle style="margin-left:10px") - el-tooltip(placement="right" content="Delete" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('view.favorite.delete_tooltip')" :disabled="hideTooltips") el-button(@click.stop="promptLocalWorldFavoriteGroupDelete(group)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") .x-friend-list(style="margin-top:10px") div(style="display:inline-block;width:300px;margin-right:15px" v-for="favorite in localWorldFavorites[group]" :key="favorite.id" @click="showWorldDialog(favorite.id)") @@ -632,22 +632,22 @@ html span.name(v-text="favorite.name") span.extra(v-if="favorite.occupants") {{ favorite.authorName }} ({{ favorite.occupants }}) span.extra(v-else v-text="favorite.authorName") - el-tooltip(placement="right" content="Unfavorite" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('view.favorite.unfavorite_tooltip')" :disabled="hideTooltips") el-button(@click.stop="removeLocalWorldFavorite(favorite.id, group)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") template(v-else) span(v-text="favorite.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="removeLocalWorldFavorite(favorite.id, group)" style="margin-left:5px") - el-tab-pane(label="Avatars") + el-tab-pane(:label="$t('view.favorite.avatars.header')") el-collapse(v-if="$refs.menu && $refs.menu.activeIndex === 'favorite' && $refs.favoriteTabRef && $refs.favoriteTabRef.currentName === '2'" style="border:0") - el-button(size="small" @click="showAvatarExportDialog") Export - el-button(size="small" @click="showAvatarImportDialog") Import + el-button(size="small" @click="showAvatarExportDialog") {{ $t('view.favorite.export') }} + el-button(size="small" @click="showAvatarImportDialog") {{ $t('view.favorite.import') }} el-collapse-item(v-for="group in API.favoriteAvatarGroups" :key="group.name") template(slot="title") span(v-text="group.displayName" style="font-weight:bold;font-size:14px;margin-left:10px") span(style="color:#909399;font-size:12px;margin-left:10px") {{ group.count }}/{{ group.capacity }} - el-tooltip(placement="top" content="Rename" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.favorite.rename_tooltip')" :disabled="hideTooltips") el-button(@click.stop="changeFavoriteGroupName(group)" size="mini" icon="el-icon-edit" circle style="margin-left:10px") - el-tooltip(placement="right" content="Clear" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('view.favorite.clear_tooltip')" :disabled="hideTooltips") el-button(@click.stop="clearFavoriteGroup(group)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") .x-friend-list(v-if="group.count" style="margin-top:10px") div(style="display:inline-block;width:300px;margin-right:15px" v-for="favorite in favoriteAvatars" v-if="favorite.groupKey === group.key" :key="favorite.id" @click="showAvatarDialog(favorite.id)") @@ -658,13 +658,13 @@ html .detail span.name(v-text="favorite.ref.name") span.extra(v-text="favorite.ref.authorName") - el-tooltip(placement="left" content="Move" :disabled="hideTooltips") + el-tooltip(placement="left" :content="$t('view.favorite.move_tooltip')" :disabled="hideTooltips") el-dropdown(trigger="click" @click.native.stop size="mini" style="margin-left:5px") el-button(type="default" icon="el-icon-back" size="mini" circle) el-dropdown-menu(#default="dropdown") template(v-if="groupAPI.name !== group.name" v-for="groupAPI in API.favoriteAvatarGroups" :key="groupAPI.name") el-dropdown-item(style="display:block;margin:10px 0" @click.native="moveFavorite(favorite.ref, groupAPI, 'avatar')" :disabled="groupAPI.count >= groupAPI.capacity") {{ groupAPI.displayName }} ({{ groupAPI.count }} / {{ groupAPI.capacity }}) - el-tooltip(placement="right" content="Unfavorite" :disabled="hideTooltips") + el-tooltip(placement="right" :content="$t('view.favorite.unfavorite_tooltip')" :disabled="hideTooltips") el-button(@click.stop="deleteFavorite(favorite.id)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") template(v-else) .detail @@ -696,23 +696,23 @@ html data-tables(v-bind="friendLogTable") template(#tool) div(style="margin:0 0 10px;display:flex;align-items:center") - el-select(v-model="friendLogTable.filters[0].value" @change="saveTableFilters" multiple clearable collapse-tags style="flex:1" placeholder="Filter") + el-select(v-model="friendLogTable.filters[0].value" @change="saveTableFilters" multiple clearable collapse-tags style="flex:1" :placeholder="$t('view.friend_log.filter_placeholder')") el-option(v-once v-for="type in ['Friend', 'Unfriend', 'FriendRequest', 'CancelFriendRequest', 'DisplayName', 'TrustLevel']" :key="type" :label="type" :value="type") - el-input(v-model="friendLogTable.filters[1].value" placeholder="Search" style="flex:none;width:150px;margin-left:10px") - el-table-column(label="Date" prop="created_at" sortable="custom" width="120") + el-input(v-model="friendLogTable.filters[1].value" :placeholder="$t('view.friend_log.search_placeholder')" style="flex:none;width:150px;margin-left:10px") + el-table-column(:label="$t('table.friendLog.date')" prop="created_at" sortable="custom" width="120") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created_at | formatDate('long') }} span {{ scope.row.created_at | formatDate('short') }} - el-table-column(label="Type" prop="type" width="150") - el-table-column(label="User" prop="displayName") + el-table-column(:label="$t('table.friendLog.type')" prop="type" width="150") + el-table-column(:label="$t('table.friendLog.user')" prop="displayName") template(v-once #default="scope") - span(v-if="scope.row.type === 'DisplayName'") {{ scope.row.previousDisplayName }} #[i.el-icon-right] + span(v-if="scope.row.type === 'DisplayName'") {{ scope.row.previousDisplayName }} #[i.el-icon-right] span.x-link(v-text="scope.row.displayName || scope.row.userId" @click="showUserDialog(scope.row.userId)") template(v-if="scope.row.type === 'TrustLevel'") span ({{ scope.row.previousTrustLevel }} #[i.el-icon-right] {{ scope.row.trustLevel }}) - el-table-column(label="Action" width="80" align="right") + el-table-column(:label="$t('table.friendLog.action')" width="80" align="right") template(v-once #default="scope") el-button(type="text" icon="el-icon-close" size="mini" @click="deleteFriendLog(scope.row)") @@ -721,25 +721,25 @@ html data-tables(v-bind="playerModerationTable" v-loading="API.isPlayerModerationsLoading") template(#tool) div(style="margin:0 0 10px;display:flex;align-items:center") - el-select(v-model="playerModerationTable.filters[0].value" @change="saveTableFilters" multiple clearable collapse-tags style="flex:1" placeholder="Filter") + el-select(v-model="playerModerationTable.filters[0].value" @change="saveTableFilters" multiple clearable collapse-tags style="flex:1" :placeholder="$t('view.moderation.filter_placeholder')") el-option(v-once v-for="type in ['block', 'unblock', 'mute', 'unmute', 'interactOn', 'interactOff']" :key="type" :label="type" :value="type") - el-input(v-model="playerModerationTable.filters[1].value" placeholder="Search" style="flex:none;width:150px;margin:0 10px") - el-tooltip(placement="bottom" content="Refresh" :disabled="hideTooltips") + el-input(v-model="playerModerationTable.filters[1].value" :placeholder="$t('view.moderation.search_placeholder')" style="flex:none;width:150px;margin:0 10px") + el-tooltip(placement="bottom" :content="$t('view.moderation.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" :loading="API.isPlayerModerationsLoading" @click="API.refreshPlayerModerations()" icon="el-icon-refresh" circle style="flex:none") - el-table-column(label="Date" prop="created" sortable="custom" width="120") + el-table-column(:label="$t('table.moderation.date')" prop="created" sortable="custom" width="120") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created | formatDate('long') }} span {{ scope.row.created | formatDate('short') }} - el-table-column(label="Type" prop="type" width="100") - el-table-column(label="Source" prop="sourceDisplayName") + el-table-column(:label="$t('table.moderation.type')" prop="type" width="100") + el-table-column(:label="$t('table.moderation.source')" prop="sourceDisplayName") template(v-once #default="scope") span.x-link(v-text="scope.row.sourceDisplayName" @click="showUserDialog(scope.row.sourceUserId)") - el-table-column(label="Target" prop="targetDisplayName") + el-table-column(:label="$t('table.moderation.target')" prop="targetDisplayName") template(v-once #default="scope") span.x-link(v-text="scope.row.targetDisplayName" @click="showUserDialog(scope.row.targetUserId)") - el-table-column(label="Action" width="80" align="right") + el-table-column(:label="$t('table.moderation.action')" width="80" align="right") template(v-once #default="scope") el-button(v-if="scope.row.sourceUserId === API.currentUser.id" type="text" icon="el-icon-close" size="mini" @click="deletePlayerModeration(scope.row)") @@ -748,18 +748,18 @@ html data-tables(v-bind="notificationTable") template(#tool) div(style="margin:0 0 10px;display:flex;align-items:center") - el-select(v-model="notificationTable.filters[0].value" @change="saveTableFilters" multiple clearable collapse-tags style="flex:1" placeholder="Filter") + el-select(v-model="notificationTable.filters[0].value" @change="saveTableFilters" multiple clearable collapse-tags style="flex:1" :placeholder="$t('view.notification.filter_placeholder')") el-option(v-once v-for="type in ['requestInvite', 'invite', 'requestInviteResponse', 'inviteResponse', 'friendRequest', 'hiddenFriendRequest', 'message', 'group.announcement', 'group.informative', 'group.invite', 'group.joinRequest', 'moderation.warning.group']" :key="type" :label="type" :value="type") - el-input(v-model="notificationTable.filters[1].value" placeholder="Search" style="flex:none;width:150px;margin:0 10px") - el-tooltip(placement="bottom" content="Refresh" :disabled="hideTooltips") + el-input(v-model="notificationTable.filters[1].value" :placeholder="$t('view.notification.search_placeholder')" style="flex:none;width:150px;margin:0 10px") + el-tooltip(placement="bottom" :content="$t('view.notification.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" :loading="API.isNotificationsLoading" @click="API.refreshNotifications()" icon="el-icon-refresh" circle style="flex:none") - el-table-column(label="Date" prop="created_at" sortable="custom" width="120") + el-table-column(:label="$t('table.notification.date')" prop="created_at" sortable="custom" width="120") template(v-once #default="scope") el-tooltip(placement="right") template(#content) span {{ scope.row.created_at | formatDate('long') }} span {{ scope.row.created_at | formatDate('short') }} - el-table-column(label="Type" prop="type" width="160") + el-table-column(:label="$t('table.notification.type')" prop="type" width="160") template(v-once #default="scope") el-tooltip(v-if="scope.row.type === 'invite'" placement="top") template(#content) @@ -769,10 +769,10 @@ html el-tooltip(placement="top" :content="scope.row.linkText" :disabled="hideTooltips") span.x-link(v-text="scope.row.type" @click="openNotificationLink(scope.row.link)") span(v-else v-text="scope.row.type") - el-table-column(label="User" prop="senderUsername" width="150") + el-table-column(:label="$t('table.notification.user')" prop="senderUsername" width="150") template(v-once #default="scope") span.x-link(v-text="scope.row.senderUsername" @click="showUserDialog(scope.row.senderUserId)") - el-table-column(label="Photo" width="100" prop="photo") + el-table-column(:label="$t('table.notification.photo')" width="100" prop="photo") template(v-once #default="scope") template(v-if="scope.row.details && scope.row.details.imageUrl") el-popover(placement="right" width="500px" trigger="click") @@ -782,14 +782,14 @@ html el-popover(placement="right" width="500px" trigger="click") img.x-link(slot="reference" v-lazy="scope.row.imageUrl" style="flex:none;width:90px;border-radius:4px") img.x-link(v-lazy="scope.row.imageUrl" style="width:500px" @click="downloadAndSaveImage(scope.row.imageUrl)") - el-table-column(label="Message" prop="message") + el-table-column(:label="$t('table.notification.message')" prop="message") template(v-once #default="scope") span(v-if="scope.row.title") {{ scope.row.title }}, {{ scope.row.message }} span(v-else-if="scope.row.message" v-text="scope.row.message") span(v-else-if='scope.row.details && scope.row.details.inviteMessage' v-text="scope.row.details.inviteMessage") span(v-else-if='scope.row.details && scope.row.details.requestMessage' v-text="scope.row.details.requestMessage") span(v-else-if='scope.row.details && scope.row.details.responseMessage' v-text="scope.row.details.responseMessage") - el-table-column(label="Action" width="100" align="right") + el-table-column(:label="$t('table.notification.action')" width="100" align="right") template(v-once #default="scope") template(v-if="scope.row.senderUserId !== API.currentUser.id && !scope.row.$isExpired") template(v-if="scope.row.type === 'friendRequest'") @@ -836,7 +836,7 @@ html //- profile .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'profile'") div.options-container(style="margin-top:0") - span.header Profile + span.header {{ $t('view.profile.profile.header') }} .x-friend-list(style="margin-top:10px") .x-friend-item(@click="showUserDialog(API.currentUser.id)") .avatar @@ -846,29 +846,29 @@ html span.extra(v-text="API.currentUser.username") .x-friend-item(style="cursor:default") .detail - span.name Last Activity + span.name {{ $t('view.profile.profile.last_activity') }} span.extra {{ API.currentUser.last_activity | formatDate('long') }} .x-friend-item(style="cursor:default") .detail - span.name Two-Factor Auth (2FA) - span.extra {{ API.currentUser.twoFactorAuthEnabled ? 'Enabled' : 'Disabled' }} + span.name {{ $t('view.profile.profile.two_factor') }} + span.extra {{ API.currentUser.twoFactorAuthEnabled ? $t('view.profile.profile.two_factor_enabled') : $t('view.profile.profile.two_factor_disabled') }} div - el-button(size="small" icon="el-icon-switch-button" @click="logout()" style="margin-left:0;margin-right:5px;margin-top:10px") Logout - el-button(size="small" icon="el-icon-printer" @click="showExportFriendsListDialog()" style="margin-left:0;margin-right:5px;margin-top:10px") Export Friends List - el-button(size="small" icon="el-icon-user" @click="showExportAvatarsListDialog()" style="margin-left:0;margin-right:5px;margin-top:10px") Export Own Avatars - el-button(size="small" icon="el-icon-chat-dot-round" @click="showDiscordNamesDialog()" style="margin-left:0;margin-right:5px;margin-top:10px") Discord Names - el-button(size="small" icon="el-icon-document-copy" @click="showNoteExportDialog()" style="margin-left:0;margin-right:5px;margin-top:10px") Export Notes + el-button(size="small" icon="el-icon-switch-button" @click="logout()" style="margin-left:0;margin-right:5px;margin-top:10px") {{ $t('view.profile.profile.logout') }} + el-button(size="small" icon="el-icon-printer" @click="showExportFriendsListDialog()" style="margin-left:0;margin-right:5px;margin-top:10px") {{ $t('view.profile.profile.export_friend_list') }} + el-button(size="small" icon="el-icon-user" @click="showExportAvatarsListDialog()" style="margin-left:0;margin-right:5px;margin-top:10px") {{ $t('view.profile.profile.export_own_avatars') }} + el-button(size="small" icon="el-icon-chat-dot-round" @click="showDiscordNamesDialog()" style="margin-left:0;margin-right:5px;margin-top:10px") {{ $t('view.profile.profile.discord_names') }} + el-button(size="small" icon="el-icon-document-copy" @click="showNoteExportDialog()" style="margin-left:0;margin-right:5px;margin-top:10px") {{ $t('view.profile.profile.export_notes') }} div.options-container - span.header Game Info + span.header {{ $t('view.profile.game_info.header') }} .x-friend-list(style="margin-top:10px") .x-friend-item .detail(@click="API.getVisits()") - span.name Online Users - span.extra(v-if="visits") {{visits}} users online. - span.extra(v-else) Click to refresh + span.name {{ $t('view.profile.game_info.online_users') }} + span.extra(v-if="visits") {{ $t('view.profile.game_info.user_online', { count: visits }) }} + span.extra(v-else) {{ $t('view.profile.game_info.refresh') }} div.options-container - span.header VRC SDK Downloads - el-tooltip(placement="top" content="Refresh" :disabled="hideTooltips") + span.header {{ $t('view.profile.vrc_sdk_downloads.header') }} + el-tooltip(placement="top" :content="$t('view.profile.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="API.getConfig()" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") .x-friend-list(style="margin-top:10px") .x-friend-item(v-for="(link, item) in API.cachedConfig.downloadUrls" :key="item" placement="top") @@ -876,18 +876,18 @@ html span.name(v-text="item") span.extra(v-text="link") div.options-container - span.header Direct Access + span.header {{ $t('view.profile.direct_access.header') }} div(style="margin-top:10px") el-button-group - el-button(size="small" @click="promptUsernameDialog()") Username - el-button(size="small" @click="promptUserIdDialog()") User ID - el-button(size="small" @click="promptWorldDialog()") World/Instance - el-button(size="small" @click="promptAvatarDialog()") Avatar + el-button(size="small" @click="promptUsernameDialog()") {{ $t('view.profile.direct_access.username') }} + el-button(size="small" @click="promptUserIdDialog()") {{ $t('view.profile.direct_access.user_id') }} + el-button(size="small" @click="promptWorldDialog()") {{ $t('view.profile.direct_access.world_instance') }} + el-button(size="small" @click="promptAvatarDialog()") {{ $t('view.profile.direct_access.avatar') }} div.options-container - span.header Invite Messages - el-tooltip(placement="top" content="Refresh" :disabled="hideTooltips") + span.header {{ $t('view.profile.invite_messages') }} + el-tooltip(placement="top" :content="$t('view.profile.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="inviteMessageTable.visible = true; refreshInviteMessageTable('message')" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") - el-tooltip(placement="top" content="Clear results" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.profile.clear_results_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="inviteMessageTable.visible = false" size="mini" icon="el-icon-delete" circle style="margin-left:5px") data-tables(v-if="inviteMessageTable.visible" v-bind="inviteMessageTable" style="margin-top:10px") el-table-column(label="Slot" prop="slot" sortable="custom" width="70") @@ -899,10 +899,10 @@ html template(v-once #default="scope") el-button(type="text" icon="el-icon-edit" size="mini" @click="showEditInviteMessageDialog('message', scope.row)") div.options-container - span.header Invite Response Messages - el-tooltip(placement="top" content="Refresh" :disabled="hideTooltips") + span.header {{ $t('view.profile.invite_response_messages') }} + el-tooltip(placement="top" :content="$t('view.profile.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="inviteResponseMessageTable.visible = true; refreshInviteMessageTable('response')" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") - el-tooltip(placement="top" content="Clear results" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.profile.clear_results_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="inviteResponseMessageTable.visible = false" size="mini" icon="el-icon-delete" circle style="margin-left:5px") data-tables(v-if="inviteResponseMessageTable.visible" v-bind="inviteResponseMessageTable" style="margin-top:10px") el-table-column(label="Slot" prop="slot" sortable="custom" width="70") @@ -914,10 +914,10 @@ html template(v-once #default="scope") el-button(type="text" icon="el-icon-edit" size="mini" @click="showEditInviteMessageDialog('response', scope.row)") div.options-container - span.header Invite Request Messages - el-tooltip(placement="top" content="Refresh" :disabled="hideTooltips") + span.header {{ $t('view.profile.invite_request_messages') }} + el-tooltip(placement="top" :content="$t('view.profile.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="inviteRequestMessageTable.visible = true; refreshInviteMessageTable('request')" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") - el-tooltip(placement="top" content="Clear results" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.profile.clear_results_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="inviteRequestMessageTable.visible = false" size="mini" icon="el-icon-delete" circle style="margin-left:5px") data-tables(v-if="inviteRequestMessageTable.visible" v-bind="inviteRequestMessageTable" style="margin-top:10px") el-table-column(label="Slot" prop="slot" sortable="custom" width="70") @@ -929,10 +929,10 @@ html template(v-once #default="scope") el-button(type="text" icon="el-icon-edit" size="mini" @click="showEditInviteMessageDialog('request', scope.row)") div.options-container - span.header Invite Request Response Messages - el-tooltip(placement="top" content="Refresh" :disabled="hideTooltips") + span.header {{ $t('view.profile.invite__request_response_messages') }} + el-tooltip(placement="top" :content="$t('view.profile.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="inviteRequestResponseMessageTable.visible = true; refreshInviteMessageTable('requestResponse')" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") - el-tooltip(placement="top" content="Clear results" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.profile.clear_results_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="inviteRequestResponseMessageTable.visible = false" size="mini" icon="el-icon-delete" circle style="margin-left:5px") data-tables(v-if="inviteRequestResponseMessageTable.visible" v-bind="inviteRequestResponseMessageTable" style="margin-top:10px") el-table-column(label="Slot" prop="slot" sortable="custom" width="70") @@ -944,17 +944,17 @@ html template(v-once #default="scope") el-button(type="text" icon="el-icon-edit" size="mini" @click="showEditInviteMessageDialog('requestResponse', scope.row)") div.options-container - span.header Past Display Names + span.header {{ $t('view.profile.past_display_names') }} data-tables(v-bind="pastDisplayNameTable" style="margin-top:10px") el-table-column(label="Date" prop="updated_at" sortable="custom") template(v-once #default="scope") span {{ scope.row.updated_at | formatDate('long') }} el-table-column(label="Name" prop="displayName") div.options-container - span.header Config JSON - el-tooltip(placement="top" content="Refresh" :disabled="hideTooltips") + span.header {{ $t('view.profile.config_json') }} + el-tooltip(placement="top" :content="$t('view.profile.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="refreshConfigTreeData()" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") - el-tooltip(placement="top" content="Clear results" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.profile.clear_results_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="configTreeData = []" size="mini" icon="el-icon-delete" circle style="margin-left:5px") el-tree(v-if="configTreeData.length > 0" :data="configTreeData" style="margin-top:10px;font-size:12px") template(#default="scope") @@ -962,10 +962,10 @@ html span(v-text="scope.data.key" style="font-weight:bold;margin-right:5px") span(v-if="!scope.data.children" v-text="scope.data.value") div.options-container - span.header Current User JSON - el-tooltip(placement="top" content="Refresh" :disabled="hideTooltips") + span.header {{ $t('view.profile.current_user_json') }} + el-tooltip(placement="top" :content="$t('view.profile.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="refreshCurrentUserTreeData()" size="mini" icon="el-icon-refresh" circle style="margin-left:5px") - el-tooltip(placement="top" content="Clear results" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.profile.clear_results_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="currentUserTreeData = []" size="mini" icon="el-icon-delete" circle style="margin-left:5px") el-tree(v-if="currentUserTreeData.length > 0" :data="currentUserTreeData" style="margin-top:10px;font-size:12px") template(#default="scope") @@ -976,230 +976,230 @@ html //- friends list .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'friendsList'" v-if="$refs.menu && $refs.menu.activeIndex === 'friendsList'") div.options-container(style="margin-top:0") - span.header Friends List + span.header {{ $t('view.friend_list.header') }} div(style="float:right;font-size:13px") div(v-if="friendsListBulkUnfriendMode" style="display:inline-block;margin-right:10px") - el-button(size="small" @click="showBulkUnfriendSelectionConfirm") Bulk Unfriend Selection + el-button(size="small" @click="showBulkUnfriendSelectionConfirm") {{ $t('view.friend_list.bulk_unfriend_selection') }} //- el-button(size="small" @click="showBulkUnfriendAllConfirm" style="margin-right:5px") Bulk Unfriend All div(style="display:inline-block;margin-right:10px") - span.name Bulk Unfriend Mode + span.name {{ $t('view.friend_list.bulk_unfriend') }} el-switch(v-model="friendsListBulkUnfriendMode" style="margin-left:5px") - span Load missing entries - el-tooltip(placement="top" style="margin-left:5px" content="This takes a lot of API requests so use it sparingly") + span {{ $t('view.friend_list.load') }} + el-tooltip(placement="top" style="margin-left:5px" :content="$t('view.friend_list.load_notice')") i.el-icon-warning template(v-if="friendsListLoading") span(v-text="friendsListLoadingProgress" style="margin-left:5px") - el-tooltip(placement="top" content="Cancel" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.friend_list.cancel_tooltip')" :disabled="hideTooltips") el-button(@click="friendsListLoading = false" size="mini" icon="el-icon-loading" circle style="margin-left:5px") template(v-else) - el-tooltip(placement="top" content="Load" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.friend_list.load_tooltip')" :disabled="hideTooltips") el-button(@click="friendsListLoadUsers" size="mini" icon="el-icon-refresh-left" circle style="margin-left:5px") div(style="margin:10px 0 0 10px;display:flex;align-items:center") div(style="flex:none;margin-right:10px") - el-tooltip(placement="bottom" content="Filter VIP only" :disabled="hideTooltips") + el-tooltip(placement="bottom" :content="$t('view.friend_list.favorites_only_tooltip')" :disabled="hideTooltips") el-switch(v-model="friendsListSearchFilterVIP" @change="friendsListSearchChange" active-color="#13ce66") - el-input(v-model="friendsListSearch" placeholder="Search" @change="friendsListSearchChange" clearable style="flex:1") - el-select(v-model="friendsListSearchFilters" multiple clearable collapse-tags style="flex:none;width:200px;margin:0 10px" @change="friendsListSearchChange" placeholder="Filter") + el-input(v-model="friendsListSearch" :placeholder="$t('view.friend_list.search_placeholder')" @change="friendsListSearchChange" clearable style="flex:1") + el-select(v-model="friendsListSearchFilters" multiple clearable collapse-tags style="flex:none;width:200px;margin:0 10px" @change="friendsListSearchChange" :placeholder="$t('view.friend_list.filter_placeholder')") el-option(v-once v-for="type in ['Display Name', 'User Name', 'Rank', 'Status', 'Bio', 'Memo']" :key="type" :label="type" :value="type") - el-tooltip(placement="top" content="Refresh" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.friend_list.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="friendsListSearchChange" icon="el-icon-refresh" circle style="flex:none") - el-tooltip(placement="top" content="Clear results" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('view.friend_list.clear_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="friendsListTable.data = []" icon="el-icon-delete" circle style="flex:none;margin-left:5px") data-tables(v-bind="friendsListTable" @row-click="selectFriendsListRow" style="margin-top:10px;cursor:pointer") el-table-column(v-if="friendsListBulkUnfriendMode" width="55" prop="$selected") template(v-once #default="scope") el-button(type="text" size="mini" @click.stop) el-checkbox(v-model="scope.row.$selected") - el-table-column(label="No." width="70" prop="$friendNum" sortable="custom") - el-table-column(label="Avatar" width="70" prop="photo") + el-table-column(:label="$t('table.friendList.no')" width="70" prop="$friendNum" sortable="custom") + el-table-column(:label="$t('table.friendList.avatar')" width="70" prop="photo") template(v-once #default="scope") el-popover(placement="right" height="500px" trigger="hover") img.friends-list-avatar(slot="reference" v-lazy="userImage(scope.row)") img.friends-list-avatar(v-lazy="userImageFull(scope.row)" style="height:500px;cursor:pointer" @click="downloadAndSaveImage(userImageFull(scope.row))") - el-table-column(label="Display Name" min-width="140" prop="displayName" sortable :sort-method="(a, b) => sortAlphabetically(a, b, 'displayName')") + el-table-column(:label="$t('table.friendList.displayName')" min-width="140" prop="displayName" sortable :sort-method="(a, b) => sortAlphabetically(a, b, 'displayName')") template(v-once #default="scope") span.name(v-if="randomUserColours" v-text="scope.row.displayName" :style="{'color':scope.row.$userColour}") span.name(v-else v-text="scope.row.displayName") - el-table-column(label="Rank" width="110" prop="$trustSortNum" sortable="custom") + el-table-column(:label="$t('table.friendList.rank')" width="110" prop="$trustSortNum" sortable="custom") template(v-once #default="scope") span.name(v-if="randomUserColours" v-text="scope.row.$trustLevel" :class="scope.row.$trustClass") span.name(v-else v-text="scope.row.$trustLevel" :style="{'color':scope.row.$userColour}") - el-table-column(label="Status" min-width="180" prop="status" sortable :sort-method="(a, b) => sortStatus(a.status, b.status)") + el-table-column(:label="$t('table.friendList.status')" min-width="180" prop="status" sortable :sort-method="(a, b) => sortStatus(a.status, b.status)") template(v-once #default="scope") i.x-user-status(v-if="scope.row.status !== 'offline'" :class="statusClass(scope.row.status)") span ‎ span(v-text="scope.row.statusDescription") - el-table-column(label="Language" width="110" prop="$languages" sortable :sort-method="(a, b) => sortLanguages(a, b)") + el-table-column(:label="$t('table.friendList.language')" width="110" prop="$languages" sortable :sort-method="(a, b) => sortLanguages(a, b)") template(v-once #default="scope") el-tooltip(v-for="item in scope.row.$languages" :key="item.key" placement="top") template(#content) span {{ item.value }} ({{ item.key }}) span.flags(:class="languageClass(item.key)" style="display:inline-block;margin-left:5px") - el-table-column(label="Bio Links" width="100" prop="bioLinks") + el-table-column(:label="$t('table.friendList.bioLink')" width="100" prop="bioLinks") template(v-once #default="scope") el-tooltip(v-if="link" v-for="(link, index) in scope.row.bioLinks" :key="index") template(#content) span(v-text="link") img(:src="getFaviconUrl(link)" style="width:16px;height:16px;vertical-align:middle;margin-right:5px;cursor:pointer" @click.stop="openExternalLink(link)") - el-table-column(label="Join Count" width="120" prop="$joinCount" sortable) - el-table-column(label="Time Together" width="140" prop="$timeSpent" sortable) + el-table-column(:label="$t('table.friendList.joinCount')" width="120" prop="$joinCount" sortable) + el-table-column(:label="$t('table.friendList.timeTogether')" width="140" prop="$timeSpent" sortable) template(v-once #default="scope") span(v-if="scope.row.$timeSpent") {{ scope.row.$timeSpent | timeToText }} - el-table-column(label="Last Seen" width="170" prop="$lastSeen" sortable :sort-method="(a, b) => sortAlphabetically(a, b, '$lastSeen')") + el-table-column(:label="$t('table.friendList.lastSeen')" width="170" prop="$lastSeen" sortable :sort-method="(a, b) => sortAlphabetically(a, b, '$lastSeen')") template(v-once #default="scope") span {{ scope.row.$lastSeen | formatDate('long') }} - el-table-column(label="Last Activity" width="170" prop="last_activity" sortable :sort-method="(a, b) => sortAlphabetically(a, b, 'last_activity')") + el-table-column(:label="$t('table.friendList.lastActivity')" width="170" prop="last_activity" sortable :sort-method="(a, b) => sortAlphabetically(a, b, 'last_activity')") template(v-once #default="scope") span {{ scope.row.last_activity | formatDate('long') }} - el-table-column(label="Last Login" width="170" prop="last_login" sortable :sort-method="(a, b) => sortAlphabetically(a, b, 'last_login')") + el-table-column(:label="$t('table.friendList.lastLogin')" width="170" prop="last_login" sortable :sort-method="(a, b) => sortAlphabetically(a, b, 'last_login')") template(v-once #default="scope") span {{ scope.row.last_login | formatDate('long') }} - el-table-column(label="Date Joined" width="120" prop="date_joined" sortable :sort-method="(a, b) => sortAlphabetically(a, b, 'date_joined')") - el-table-column(label="Unfriend" width="80") + el-table-column(:label="$t('table.friendList.dateJoined')" width="120" prop="date_joined" sortable :sort-method="(a, b) => sortAlphabetically(a, b, 'date_joined')") + el-table-column(:label="$t('table.friendList.unfriend')" width="80") template(v-once #default="scope") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="confirmDeleteFriend(scope.row.id)") //- settings .x-container(v-show="$refs.menu && $refs.menu.activeIndex === 'settings'") - div.options-container(style="margin-top:0") - span.header Settings + div.options-container(style="margin-top:0") + span.header {{ $t("view.settings.header") }} el-tabs(type="card" style="margin-top:10px") - el-tab-pane(label="General") + el-tab-pane(:label="$t('view.settings.category.general')") div.options-container(style="margin-top:0") - span.header General + span.header {{ $t("view.settings.general.general.header") }} .x-friend-list(style="margin-top:10px") .x-friend-item(style="cursor:default") .detail - span.name Version + span.name {{ $t("view.settings.general.general.version") }} span.extra(v-text="appVersion") .x-friend-item(@click="checkForVRCXUpdate") .detail - span.name Latest Version + span.name {{ $t("view.settings.general.general.latest_app_version") }} span.extra(v-if="latestAppVersion" v-text="latestAppVersion") - span.extra(v-else) Click to refresh + span.extra(v-else) {{ $t("view.settings.general.general.latest_app_version_refresh") }} .x-friend-item(@click="openExternalLink('https://github.com/pypy-vrc/VRCX')") .detail - span.name Repository URL + span.name {{ $t("view.settings.general.general.repository_url") }} span.extra https://github.com/pypy-vrc/VRCX .x-friend-item(@click="openExternalLink('https://vrcx.pypy.moe/discord')") .detail - span.name Support + span.name {{ $t("view.settings.general.general.support") }} span.extra https://vrcx.pypy.moe/discord div.options-container - span.header VRCX Updater + span.header {{ $t("view.settings.general.vrcx_updater.header") }} div.options-container-item - el-button(size="small" icon="el-icon-upload" @click="showVRCXUpdateDialog()") Change build + el-button(size="small" icon="el-icon-upload" @click="showVRCXUpdateDialog()") {{ $t("view.settings.general.vrcx_updater.change_build") }} div.options-container-item - span.name Auto update: + span.name {{ $t("view.settings.general.vrcx_updater.auto_update") }} br el-radio-group(v-model="autoUpdateVRCX" @change="saveAutoUpdateVRCX" size="mini") - el-radio-button(label="Off") - el-radio-button(label="Notify") - el-radio-button(label="Auto Download") - el-radio-button(label="Auto Install") + el-radio-button(label="Off") {{ $t("view.settings.general.vrcx_updater.auto_update_off") }} + el-radio-button(label="Notify") {{ $t("view.settings.general.vrcx_updater.auto_update_notify") }} + el-radio-button(label="Auto Download") {{ $t("view.settings.general.vrcx_updater.auto_update_download") }} + el-radio-button(label="Auto Install") {{ $t("view.settings.general.vrcx_updater.auto_update_install") }} div.options-container - span.header Application + span.header {{ $t("view.settings.general.application.header") }} div.options-container-item - span.name Start at Windows startup + span.name {{ $t("view.settings.general.application.startup") }} el-switch(v-model="isStartAtWindowsStartup") div.options-container-item - span.name Start as minimized state + span.name {{ $t("view.settings.general.application.minimized") }} el-switch(v-model="isStartAsMinimizedState") div.options-container-item - span.name Close to tray + span.name {{ $t("view.settings.general.application.tray") }} el-switch(v-model="isCloseToTray") div.options-container div.options-container(style="margin-top:45px;border-top:1px solid #eee;padding-top:30px") - span.header Legal Notice + span.header {{ $t("view.settings.general.legal_notice.header" )}} div.options-container-item p © 2019-2022 #[a(@click="openExternalLink('https://github.com/pypy-vrc')") pypy] (mina#5656) & #[a(@click="openExternalLink('https://github.com/Natsumi-sama')") Natsumi] - p VRCX is an assistant application for provide information about manage friendship. this application uses unofficial VRChat API (VRCSDK). - p VRCX isn't endorsed by VRChat and doesn't reflect the views or opinions of VRChat or anyone officially involved in producing or managing VRChat. VRChat is trademark of VRChat Inc. VRChat © VRChat Inc. - p pypy or Natsumi aren't responsible for any problems caused by VRCX. Use at your own risk! + p {{ $t("view.settings.general.legal_notice.info" )}} + p {{ $t("view.settings.general.legal_notice.disclaimer1" )}} + p {{ $t("view.settings.general.legal_notice.disclaimer2" )}} div.options-container-item - el-button(@click="ossDialog = true" size="small") Open Source Software Notice - el-tab-pane(label="Appearance") + el-button(@click="ossDialog = true" size="small") {{ $t("view.settings.general.legal_notice.open_source_software_notice" )}} + el-tab-pane(:label="$t('view.settings.category.appearance')") div.options-container(style="margin-top:0") - span.header Appearance + span.header {{ $t("view.settings.appearance.appearance.header") }} div.options-container-item - span.name Theme mode + span.name {{ $t('view.settings.appearance.appearance.theme_mode') }} el-radio-group(v-model="themeMode" size="mini") - el-radio-button(label="system") System - el-radio-button(label="light") Light - el-radio-button(label="dark") Dark + el-radio-button(label="system") {{ $t('view.settings.appearance.appearance.theme_mode_system') }} + el-radio-button(label="light") {{ $t('view.settings.appearance.appearance.theme_mode_light') }} + el-radio-button(label="dark") {{ $t('view.settings.appearance.appearance.theme_mode_dark') }} div.options-container-item - span.name VRCPlus Profile Icons + span.name {{ $t('view.settings.appearance.appearance.vrcplus_profile_icons') }} el-switch(v-model="displayVRCPlusIconsAsAvatar" @change="saveOpenVROption") div.options-container-item - span.name Disable Tooltips + span.name {{ $t('view.settings.appearance.appearance.disable_tooltips') }} el-switch(v-model="hideTooltips" @change="saveOpenVROption") div.options-container-item - span.name Sort Favorites By - el-switch(v-model="sortFavorites" inactive-text="name" active-text="date" @change="saveSortFavoritesOption") + span.name {{ $t('view.settings.appearance.appearance.sort_favorite_by') }} + el-switch(v-model="sortFavorites" :inactive-text="$t('view.settings.appearance.appearance.sort_favorite_by_name')" :active-text="$t('view.settings.appearance.appearance.sort_favorite_by_date')" @change="saveSortFavoritesOption") div.options-container-item - span.name Sort Instance Users By - el-switch(v-model="instanceUsersSortAlphabetical" inactive-text="time" active-text="alphabetical" @change="saveOpenVROption") + span.name {{ $t('view.settings.appearance.appearance.sort_instance_users_by') }} + el-switch(v-model="instanceUsersSortAlphabetical" :inactive-text="$t('view.settings.appearance.appearance.sort_instance_users_by_time')" :active-text="$t('view.settings.appearance.appearance.sort_instance_users_by_alphabet')" @change="saveOpenVROption") div.options-container-item - el-button(size="small" icon="el-icon-notebook-1" @click="promptMaxTableSizeDialog") Table Max Size + el-button(size="small" icon="el-icon-notebook-1" @click="promptMaxTableSizeDialog") {{ $t('view.settings.appearance.appearance.table_max_size') }} div.options-container-item el-dropdown(@click.native.stop trigger="click" size="small") el-button(size="mini") - span Page Size: {{ tablePageSize }} #[i.el-icon-arrow-down.el-icon--right] + span {{ $t('view.settings.appearance.appearance.page_size') }} {{ tablePageSize }} #[i.el-icon-arrow-down.el-icon--right] el-dropdown-menu(#default="dropdown") el-dropdown-item(v-for="(number) in [10, 15, 25, 50, 100]" v-text="number" @click.native="setTablePageSize(number)") div.options-container - span.header Timedate + span.header {{ $t('view.settings.appearance.timedate.header') }} div.options-container-item - span.name Time Format - el-switch(v-model="dtHour12" @change="setDatetimeFormat" inactive-text="24 Hour" active-text="12 Hour") + span.name {{ $t('view.settings.appearance.timedate.time_format') }} + el-switch(v-model="dtHour12" @change="setDatetimeFormat" :inactive-text="$t('view.settings.appearance.timedate.time_format_24')" :active-text="$t('view.settings.appearance.timedate.time_format_12')") div.options-container-item - span.name Force ISO date format + span.name {{ $t('view.settings.appearance.timedate.force_iso_date_format') }} el-switch(v-model="dtIsoFormat" @change="setDatetimeFormat") div.options-container - span.header Side Panel + span.header {{ $t('view.settings.appearance.side_panel.header') }} br - span.sub-header Sorting + span.sub-header {{ $t('view.settings.appearance.side_panel.sorting.header') }} div.options-container-item - span.name Sort Private to bottom + span.name {{ $t('view.settings.appearance.side_panel.sorting.sort_private_to_bottom') }} el-switch(v-model="orderFriendsGroupPrivate" @change="saveOrderFriendGroup") div.options-container-item - span.name Sort by status + span.name {{ $t('view.settings.appearance.side_panel.sorting.sort_by_status') }} el-switch(v-model="orderFriendsGroupStatus" @change="saveOrderFriendGroup") div.options-container-item - span.name Sort GPS to top + span.name {{ $t('view.settings.appearance.side_panel.sorting.sort_gps_to_top') }} el-switch(v-model="orderFriendsGroupGPS" @change="saveOrderFriendGroup") - span.name(style="margin-left:5px") (online for only) + span.name(style="margin-left:5px") {{ $t('view.settings.appearance.side_panel.sorting.sort_gps_to_top_notice') }} div.options-container-item - span.name VIP - el-switch(v-model="orderFriendsGroup0" inactive-text="alphabetical" active-text="online for" @change="saveOrderFriendGroup") + span.name {{ $t('view.settings.appearance.side_panel.sorting.sort_favorite_by') }} + el-switch(v-model="orderFriendsGroup0" :inactive-text="$t('view.settings.appearance.side_panel.sorting.sort_favorite_by_alphabet')" :active-text="$t('view.settings.appearance.side_panel.sorting.sort_favorite_by_online_time')" @change="saveOrderFriendGroup") div.options-container-item - span.name Online - el-switch(v-model="orderFriendsGroup1" inactive-text="alphabetical" active-text="online for" @change="saveOrderFriendGroup") + span.name {{ $t('view.settings.appearance.side_panel.sorting.sort_online_by') }} + el-switch(v-model="orderFriendsGroup1" :inactive-text="$t('view.settings.appearance.side_panel.sorting.sort_online_by_alphabet')" :active-text="$t('view.settings.appearance.side_panel.sorting.sort_online_by_online_time')" @change="saveOrderFriendGroup") div.options-container-item - span.name Active - el-switch(v-model="orderFriendsGroup2" inactive-text="alphabetical" active-text="online for" @change="saveOrderFriendGroup") + span.name {{ $t('view.settings.appearance.side_panel.sorting.sort_active_by') }} + el-switch(v-model="orderFriendsGroup2" :inactive-text="$t('view.settings.appearance.side_panel.sorting.sort_active_by_alphabet')" :active-text="$t('view.settings.appearance.side_panel.sorting.sort_active_by_online_time')" @change="saveOrderFriendGroup") div.options-container-item - span.name Offline - el-switch(v-model="orderFriendsGroup3" inactive-text="alphabetical" active-text="online for" @change="saveOrderFriendGroup") - span.sub-header Width + span.name {{ $t('view.settings.appearance.side_panel.sorting.sort_offline_by') }} + el-switch(v-model="orderFriendsGroup3" :inactive-text="$t('view.settings.appearance.side_panel.sorting.sort_offline_by_alphabet')" :active-text="$t('view.settings.appearance.side_panel.sorting.sort_offline_by_offline_time')" @change="saveOrderFriendGroup") + span.sub-header {{ $t('view.settings.appearance.side_panel.width') }} div.options-container-item el-slider(v-model="asideWidth" @input="setAsideWidth" :show-tooltip="false" :marks="{236: ''}" :min="141" :max="500" style="width:300px") div.options-container - span.header User Dialog + span.header {{ $t('view.settings.appearance.user_dialog.header') }} div.options-container-item - span.name Hide VRChat Notes + span.name {{ $t('view.settings.appearance.user_dialog.hide_vrchat_notes') }} el-switch(v-model="hideUserNotes" @change="saveUserDialogOption") div.options-container-item - span.name Hide VRCX Memos + span.name {{ $t('view.settings.appearance.user_dialog.hide_vrcx_memos') }} el-switch(v-model="hideUserMemos" @change="saveUserDialogOption") div.options-container-item - span.name Export VRCX memos into VRChat notes + span.name {{ $t('view.settings.appearance.user_dialog.export_vrcx_memos_into_vrchat_notes') }} br - el-button(size="small" icon="el-icon-document-copy" @click="showNoteExportDialog") Export Notes + el-button(size="small" icon="el-icon-document-copy" @click="showNoteExportDialog") {{ $t('view.settings.appearance.user_dialog.export_notes') }} div.options-container - span.header User Colours + span.header {{ $t('view.settings.appearance.user_colors.header') }} div.options-container-item - span.name Random colours from user ID + span.name {{ $t('view.settings.appearance.user_colors.random_colors_from_user_id') }} el-switch(v-model="randomUserColours" @change="updatetrustColor") div.options-container-item div @@ -1223,288 +1223,288 @@ html div el-color-picker(v-model="trustColor.troll" @change="updatetrustColor" size="mini" :predefine="['#782f2f']") span.color-picker(slot="trigger" class="x-tag-troll") Nuisance - el-tab-pane(label="Notifications") + el-tab-pane(:label="$t('view.settings.category.notifications')") div.options-container(style="margin-top:0") - span.header Notifications + span.header {{ $t('view.settings.notifications.notifications.header') }} div.options-container-item - el-button(size="small" icon="el-icon-chat-square" @click="showNotyFeedFiltersDialog") Notification Filters - span.sub-header SteamVR Notifications + el-button(size="small" icon="el-icon-chat-square" @click="showNotyFeedFiltersDialog") {{ $t('view.settings.notifications.notifications.notification_filter') }} + span.sub-header {{ $t('view.settings.notifications.notifications.steamvr_notifications.header') }} div.options-container-item - span.name SteamVR Overlay + span.name {{ $t('view.settings.notifications.notifications.steamvr_notifications.steamvr_overlay') }} el-switch(v-model="openVR" @change="saveOpenVROption") div.options-container-item - span.name Overlay Notifications + span.name {{ $t('view.settings.notifications.notifications.steamvr_notifications.overlay_notifications') }} el-switch(v-model="overlayNotifications" @change="saveOpenVROption" :disabled="!openVR") div.options-container-item - el-button(size="small" icon="el-icon-rank" @click="showNotificationPositionDialog" :disabled="!overlayNotifications || !openVR") Notification Position + el-button(size="small" icon="el-icon-rank" @click="showNotificationPositionDialog" :disabled="!overlayNotifications || !openVR") {{ $t('view.settings.notifications.notifications.steamvr_notifications.notification_position') }} div.options-container-item - span.name XSOverlay Notifications + span.name {{ $t('view.settings.notifications.notifications.steamvr_notifications.xsoverlay_notifications') }} el-switch(v-model="xsNotifications" @change="saveOpenVROption") div.options-container-item - span.name User images (slower) + span.name {{ $t('view.settings.notifications.notifications.steamvr_notifications.user_images') }} el-switch(v-model="imageNotifications" @change="saveOpenVROption") div.options-container-item - el-button(size="small" icon="el-icon-time" @click="promptNotificationTimeout" :disabled="(!overlayNotifications || !openVR) && !xsNotifications") Notification Timeout - span.sub-header Desktop Notifications + el-button(size="small" icon="el-icon-time" @click="promptNotificationTimeout" :disabled="(!overlayNotifications || !openVR) && !xsNotifications") {{ $t('view.settings.notifications.notifications.steamvr_notifications.notification_timeout') }} + span.sub-header {{ $t('view.settings.notifications.notifications.desktop_notifications.header') }} div.options-container-item - span.name When to display: + span.name {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display') }} br el-radio-group(v-model="desktopToast" @change="saveOpenVROption" size="mini") - el-radio-button(label="Never") - el-radio-button(label="Desktop Mode") - el-radio-button(label="Inside VR") - el-radio-button(label="Outside VR") - el-radio-button(label="Game Closed") - el-radio-button(label="Game Running") - el-radio-button(label="Always") + el-radio-button(label="Never") {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display_never') }} + el-radio-button(label="Desktop Mode") {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display_desktop') }} + el-radio-button(label="Inside VR") {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display_inside_vr') }} + el-radio-button(label="Outside VR") {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display_outside_vr') }} + el-radio-button(label="Game Closed") {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display_game_closed') }} + el-radio-button(label="Game Running") {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display_game_running') }} + el-radio-button(label="Always") {{ $t('view.settings.notifications.notifications.desktop_notifications.when_to_display_always') }} br - span.sub-header Text-To-Speech Options + span.sub-header {{ $t('view.settings.notifications.notifications.text_to_speech.header') }} div.options-container-item - span.name Notification TTS, When to play: + span.name {{ $t('view.settings.notifications.notifications.text_to_speech.when_to_play') }} br el-radio-group(v-model="notificationTTS" @change="saveNotificationTTS" size="mini") - el-radio-button(label="Never") - el-radio-button(label="Inside VR") - el-radio-button(label="Game Closed") - el-radio-button(label="Game Running") - el-radio-button(label="Always") + el-radio-button(label="Never") {{ $t('view.settings.notifications.notifications.text_to_speech.when_to_play_never') }} + el-radio-button(label="Inside VR") {{ $t('view.settings.notifications.notifications.text_to_speech.when_to_play_inside_vr') }} + el-radio-button(label="Game Closed") {{ $t('view.settings.notifications.notifications.text_to_speech.when_to_play_game_closed') }} + el-radio-button(label="Game Running") {{ $t('view.settings.notifications.notifications.text_to_speech.when_to_play_game_running') }} + el-radio-button(label="Always") {{ $t('view.settings.notifications.notifications.text_to_speech.when_to_play_always') }} div.options-container-item - span.name TTS Voice + span.name {{ $t('view.settings.notifications.notifications.text_to_speech.tts_voice') }} el-dropdown(@command="(voice) => changeTTSVoice(voice)" trigger="click" size="small") el-button(size="mini" :disabled="notificationTTS === 'Never'") span {{ getTTSVoiceName() }} #[i.el-icon-arrow-down.el-icon--right] el-dropdown-menu(#default="dropdown") el-dropdown-item(v-if="voice" v-for="(voice, index) in TTSvoices" :key="index" v-text="voice.name" :command="index") - el-tab-pane(label="Wrist Overlay") + el-tab-pane(:label="$t('view.settings.category.wrist_overlay')") div.options-container(style="margin-top:0") - span.header SteamVR Wrist Overlay + span.header {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.header') }} div.options-container-item - span * It runs automatically when VRChat is running. + span {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.description') }} br br - span Grip: Vive or Other Controllers Grab, Oculus X/A Buttons + span {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.grip') }} br - span Menu: Vive Menu, Index B, Oculus Y/B Buttons + span {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.menu') }} br div.options-container-item - span.name SteamVR Overlay + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.steamvr_overlay') }} el-switch(v-model="openVR" @change="saveOpenVROption") div.options-container-item - span.name Wrist Feed Overlay + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.wrist_feed_overlay') }} el-switch(v-model="overlayWrist" @change="saveOpenVROption" :disabled="!openVR") div.options-container-item - span.name Hide Private Worlds + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.hide_private_worlds') }} el-switch(v-model="hidePrivateFromFeed" @change="saveOpenVROption") div.options-container-item(style="min-width:118px") - span.name Start Overlay With + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.start_overlay_with') }} el-switch(v-model="openVRAlways" @change="saveOpenVROption" inactive-text="VRChat" active-text="SteamVR" :disabled="!openVR") div.options-container-item - span.name Overlay Button - el-switch(v-model="overlaybutton" @change="saveOpenVROption" inactive-text="Grip" active-text="Menu" :disabled="!openVR || !overlayWrist") + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.overlay_button') }} + el-switch(v-model="overlaybutton" @change="saveOpenVROption" :inactive-text="$t('view.settings.wrist_overlay.steamvr_wrist_overlay.overlay_button_grip')" :active-text="$t('view.settings.wrist_overlay.steamvr_wrist_overlay.overlay_button_menu')" :disabled="!openVR || !overlayWrist") div.options-container-item - span.name Display Overlay On + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on') }} el-radio-group(v-model="overlayHand" @change="saveOpenVROption" size="mini") - el-radio-button(label="1") Left Hand - el-radio-button(label="2") Right Hand - el-radio-button(label="0") Both Hands + el-radio-button(label="1") {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on_left') }} + el-radio-button(label="2") {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on_right') }} + el-radio-button(label="0") {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.display_overlay_on_both') }} div.options-container-item - span.name Background Colour + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.background_color') }} el-switch(v-model="vrBackgroundEnabled" @change="saveOpenVROption" :disabled="!openVR || !overlayWrist") div.options-container-item - span.name Minimal Feed Icons + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.minimal_feed_icons') }} el-switch(v-model="minimalFeed" @change="saveOpenVROption" :disabled="!openVR || !overlayWrist") div.options-container-item - span.name Hide VR Devices + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.hide_vr_devices') }} el-switch(v-model="hideDevicesFromFeed" @change="saveOpenVROption" :disabled="!openVR || !overlayWrist") div.options-container-item - span.name Hide CPU Usage + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.hide_cpu_usage') }} el-switch(v-model="hideCpuUsageFromFeed" @change="saveOpenVROption" :disabled="!openVR || !overlayWrist") div.options-container-item - span.name Hide Game Uptime + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.hide_game_uptime') }} el-switch(v-model="hideUptimeFromFeed" @change="saveOpenVROption" :disabled="!openVR || !overlayWrist") div.options-container-item - span.name Show PC Uptime + span.name {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.show_pc_uptime') }} el-switch(v-model="pcUptimeOnFeed" @change="saveOpenVROption" :disabled="!openVR || !overlayWrist") div.options-container-item - el-button(size="small" icon="el-icon-notebook-2" @click="showWristFeedFiltersDialog" :disabled="!openVR || !overlayWrist") Wrist Feed Filters - el-tab-pane(label="Discord Presence") + el-button(size="small" icon="el-icon-notebook-2" @click="showWristFeedFiltersDialog" :disabled="!openVR || !overlayWrist") {{ $t('view.settings.wrist_overlay.steamvr_wrist_overlay.wrist_feed_filters') }} + el-tab-pane(:label="$t('view.settings.category.discord_presence')") div.options-container(style="margin-top:0") - span.header Discord Presence + span.header {{ $t('view.settings.discord_presence.discord_presence.header') }} div.options-container-item - span * Only works when VRChat is running. + span {{ $t('view.settings.discord_presence.discord_presence.description') }} div.options-container-item - span.name Enable - el-tooltip(placement="top" style="margin-left:5px" content="Recommended to disable Rich Presence in VRChat config.json to stop it from conflicting") + span.name {{ $t('view.settings.discord_presence.discord_presence.enable') }} + el-tooltip(placement="top" style="margin-left:5px" :content="$t('view.settings.discord_presence.discord_presence.enable_tooltip')") i.el-icon-warning(style="cursor:pointer" @click="showVRChatConfig") el-switch(v-model="discordActive" @change="saveDiscordOption") div.options-container-item - span.name Instance type/player count + span.name {{ $t('view.settings.discord_presence.discord_presence.instance_type_player_count') }} el-switch(v-model="discordInstance" @change="saveDiscordOption" :disabled="!discordActive") div.options-container-item - span.name Join button (public only) + span.name {{ $t('view.settings.discord_presence.discord_presence.join_button') }} el-switch(v-model="discordJoinButton" @change="saveDiscordOption" :disabled="!discordActive") div.options-container-item - span.name Hide world details in private + span.name {{ $t('view.settings.discord_presence.discord_presence.hide_details_in_private') }} el-switch(v-model="discordHideInvite" @change="saveDiscordOption" :disabled="!discordActive") div.options-container-item - span.name Hide world images + span.name {{ $t('view.settings.discord_presence.discord_presence.hide_images') }} el-switch(v-model="discordHideImage" @change="saveDiscordOption" :disabled="!discordActive") - el-tab-pane(label="Advanced") + el-tab-pane(:label="$t('view.settings.category.advanced')") div.options-container(style="margin-top:0") - span.header Advanced + span.header {{ $t('view.settings.advanced.advanced.header') }} div.options-container-item el-button-group el-button(size="small" icon="el-icon-s-operation" @click="showVRChatConfig()") VRChat config.json - el-button(size="small" icon="el-icon-s-operation" @click="showLaunchOptions()") Launch Options + el-button(size="small" icon="el-icon-s-operation" @click="showLaunchOptions()") {{ $t('view.settings.advanced.advanced.launch_options') }} div.options-container - span.sub-header Pending Offline + span.sub-header {{ $t('view.settings.advanced.advanced.pending_offline.header') }} div.options-container-item - span.name Delay before marking user as offline (fixes false positives) + span.name {{ $t('view.settings.advanced.advanced.pending_offline.description') }} el-button-group(style="display:block") - el-button(size="small" icon="el-icon-s-operation" @click="promptSetPendingOffline") Set Delay - span.sub-header Primary password + el-button(size="small" icon="el-icon-s-operation" @click="promptSetPendingOffline") {{ $t('view.settings.advanced.advanced.pending_offline.set_delay') }} + span.sub-header {{ $t('view.settings.advanced.advanced.primary_password.header') }} div.options-container-item - span.name(style="min-width:300px") Encrypt password (disables auto login) + span.name(style="min-width:300px") {{ $t('view.settings.advanced.advanced.primary_password.description') }} el-switch(v-model="enablePrimaryPassword" @change="enablePrimaryPasswordChange" :disabled="!loginForm.savedCredentials[API.currentUser.username]") - span.sub-header VRChat Quit Fix + span.sub-header {{ $t('view.settings.advanced.advanced.vrchat_quit_fix.header') }} div.options-container-item - span.name(style="min-width:300px") Kill VRChat after exiting game + span.name(style="min-width:300px") {{ $t('view.settings.advanced.advanced.vrchat_quit_fix.description') }} el-switch(v-model="vrcQuitFix" @change="saveOpenVROption") - span.sub-header Automatically Manage Cache When Closing VRChat + span.sub-header {{ $t('view.settings.advanced.advanced.auto_cache_management.header') }} div.options-container-item - span.name(style="min-width:300px") Auto delete old versions from cache + span.name(style="min-width:300px") {{ $t('view.settings.advanced.advanced.auto_cache_management.description') }} el-switch(v-model="autoSweepVRChatCache" @change="saveOpenVROption") div.options-container - span.header Remote Avatar Database + span.header {{ $t('view.settings.advanced.advanced.remote_database.header') }} div.options-container-item - span.name Enable + span.name {{ $t('view.settings.advanced.advanced.remote_database.enable') }} el-switch(v-model="avatarRemoteDatabase" @change="saveOpenVROption") div.options-container-item - el-button(size="small" icon="el-icon-user-solid" @click="showAvatarProviderDialog") Avatar Database Provider + el-button(size="small" icon="el-icon-user-solid" @click="showAvatarProviderDialog") {{ $t('view.settings.advanced.advanced.remote_database.avatar_database_provider') }} div.options-container - span.header YouTube API + span.header {{ $t('view.settings.advanced.advanced.youtube_api.header') }} div.options-container-item - span.name Enabled + span.name {{ $t('view.settings.advanced.advanced.youtube_api.enable') }} el-switch(v-model="youTubeApi" @change="changeYouTubeApi") div.options-container-item - el-button(size="small" icon="el-icon-caret-right" @click="showYouTubeApiDialog") YouTube API Key - span.header Progress pie overlay for videos + el-button(size="small" icon="el-icon-caret-right" @click="showYouTubeApiDialog") {{ $t('view.settings.advanced.advanced.youtube_api.youtube_api_key') }} + span.header {{ $t('view.settings.advanced.advanced.video_progress_pie.header') }} div.options-container-item - span.name Enable - el-tooltip(placement="top" style="margin-left:5px" content="Requires SteamVR overlay to be enabled") + span.name {{ $t('view.settings.advanced.advanced.video_progress_pie.enable') }} + el-tooltip(placement="top" style="margin-left:5px" :content="$t('view.settings.advanced.advanced.video_progress_pie.enable_tooltip')") i.el-icon-warning el-switch(v-model="progressPie" @change="changeYouTubeApi" :disabled="!openVR") div.options-container-item - span.name Dance worlds only + span.name {{ $t('view.settings.advanced.advanced.video_progress_pie.dance_world_only') }} el-switch(v-model="progressPieFilter" @change="changeYouTubeApi" :disabled="!openVR") div.options-container(v-if="photonLoggingEnabled") - span.header Photon Logging Overlay + span.header {{ $t('view.settings.advanced.photon.header') }} div.options-container-item - span.sub-header Photon Event HUD + span.sub-header {{ $t('view.settings.advanced.photon.event_hud.header') }} div.options-container-item - span.name Enable - el-tooltip(placement="top" style="margin-left:5px" content="Requires SteamVR overlay to be enabled") + span.name {{ $t('view.settings.advanced.photon.event_hud.enable') }} + el-tooltip(placement="top" style="margin-left:5px" :content="$t('view.settings.advanced.photon.event_hud.enable_tooltip')") i.el-icon-warning el-switch(v-model="photonEventOverlay" @change="saveEventOverlay" :disabled="!openVR") div.options-container-item - span.name Filter + span.name {{ $t('view.settings.advanced.photon.event_hud.filter') }} el-radio-group(v-model="photonEventOverlayFilter" @change="saveEventOverlay" size="mini" :disabled="!openVR || !photonEventOverlay") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="VIP") {{ $t('view.settings.advanced.photon.event_hud.filter_favorites') }} + el-radio-button(label="Friends") {{ $t('view.settings.advanced.photon.event_hud.filter_friends') }} + el-radio-button(label="Everyone") {{ $t('view.settings.advanced.photon.event_hud.filter_everyone') }} div.options-container-item - el-button(size="small" icon="el-icon-time" @click="promptPhotonOverlayMessageTimeout" :disabled="!openVR") Message Timeout + el-button(size="small" icon="el-icon-time" @click="promptPhotonOverlayMessageTimeout" :disabled="!openVR") {{ $t('view.settings.advanced.photon.event_hud.message_timeout') }} div.options-container-item el-select(v-model="photonEventTableTypeOverlayFilter" @change="photonEventTableFilterChange" multiple clearable collapse-tags style="flex:1" placeholder="Filter") el-option(v-once v-for="type in photonEventTableTypeFilterList" :key="type" :label="type" :value="type") br - span.sub-header User timeout HUD + span.sub-header {{ $t('view.settings.advanced.photon.timeout_hud.header') }} div.options-container-item - span.name Enable - el-tooltip(placement="top" style="margin-left:5px" content="Requires SteamVR overlay to be enabled") + span.name {{ $t('view.settings.advanced.photon.timeout_hud.enable') }} + el-tooltip(placement="top" style="margin-left:5px" :content="$t('view.settings.advanced.photon.timeout_hud.enable_tooltip')") i.el-icon-warning el-switch(v-model="timeoutHudOverlay" @change="saveEventOverlay" :disabled="!openVR") div.options-container-item - span.name Filter + span.name {{ $t('view.settings.advanced.photon.timeout_hud.filter') }} el-radio-group(v-model="timeoutHudOverlayFilter" @change="saveEventOverlay" size="mini" :disabled="!openVR || !timeoutHudOverlay") - el-radio-button(label="VIP") - el-radio-button(label="Friends") - el-radio-button(label="Everyone") + el-radio-button(label="VIP") {{ $t('view.settings.advanced.photon.timeout_hud.filter_favorites') }} + el-radio-button(label="Friends") {{ $t('view.settings.advanced.photon.timeout_hud.filter_friends') }} + el-radio-button(label="Everyone") {{ $t('view.settings.advanced.photon.timeout_hud.filter_everyone') }} div.options-container-item - el-button(size="small" icon="el-icon-time" @click="promptPhotonLobbyTimeoutThreshold" :disabled="!openVR") Timeout Threshold + el-button(size="small" icon="el-icon-time" @click="promptPhotonLobbyTimeoutThreshold" :disabled="!openVR") {{ $t('view.settings.advanced.photon.timeout_hud.timeout_threshold') }} div.options-container - span.header VRCX Instance Cache/Debug + span.header {{ $t('view.settings.advanced.advanced.cache_debug.header') }} div.options-container-item - span.name Disable GameLog + span.name {{ $t('view.settings.advanced.advanced.cache_debug.disable_gamelog') }} el-switch(v-model="gameLogDisabled" @change="disableGameLogDialog") - span.name(style="margin-left:15px") (will likely break things) + span.name(style="margin-left:15px") {{ $t('view.settings.advanced.advanced.cache_debug.disable_gamelog_notice') }} div.options-container-item - span.name User cache: #[span(v-text="API.cachedUsers.size")] + span.name {{ $t('view.settings.advanced.advanced.cache_debug.user_cache') }} #[span(v-text="API.cachedUsers.size")] div.options-container-item - span.name World cache: #[span(v-text="API.cachedWorlds.size")] + span.name {{ $t('view.settings.advanced.advanced.cache_debug.world_cache') }} #[span(v-text="API.cachedWorlds.size")] div.options-container-item - span.name Avatar cache: #[span(v-text="API.cachedAvatars.size")] + span.name {{ $t('view.settings.advanced.advanced.cache_debug.avatar_cache') }} #[span(v-text="API.cachedAvatars.size")] div.options-container-item - span.name Avatar Name cache: #[span(v-text="API.cachedAvatarNames.size")] + span.name {{ $t('view.settings.advanced.advanced.cache_debug.avatar_name_cache') }} #[span(v-text="API.cachedAvatarNames.size")] div.options-container-item - el-button(size="small" icon="el-icon-delete-solid" @click="clearVRCXCache") Clear Cache - el-button(size="small" icon="el-icon-time" @click="promptAutoClearVRCXCacheFrequency") Auto Clear Cache + el-button(size="small" icon="el-icon-delete-solid" @click="clearVRCXCache") {{ $t('view.settings.advanced.advanced.cache_debug.clear_cache') }} + el-button(size="small" icon="el-icon-time" @click="promptAutoClearVRCXCacheFrequency") {{ $t('view.settings.advanced.advanced.cache_debug.auto_clear_cache') }} div.options-container-item - el-button(size="small" icon="el-icon-download" @click="showDownloadDialog") Download History - el-button(size="small" icon="el-icon-tickets" @click="showConsole") Show Console + el-button(size="small" icon="el-icon-download" @click="showDownloadDialog") {{ $t('view.settings.advanced.advanced.cache_debug.download_history') }} + el-button(size="small" icon="el-icon-tickets" @click="showConsole") {{ $t('view.settings.advanced.advanced.cache_debug.show_console') }} div.options-container - span.sub-header SQLite Table Size + span.sub-header {{ $t('view.settings.advanced.advanced.sqlite_table_size.header') }} div.options-container-item - el-button(size="small" icon="el-icon-refresh" @click="getSqliteTableSizes") Refresh + el-button(size="small" icon="el-icon-refresh" @click="getSqliteTableSizes") {{ $t('view.settings.advanced.advanced.sqlite_table_size.refresh') }} div.options-container-item - span.name GPS: #[span(v-text="sqliteTableSizes.gps")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.gps') }} #[span(v-text="sqliteTableSizes.gps")] div.options-container-item - span.name Status: #[span(v-text="sqliteTableSizes.status")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.status') }} #[span(v-text="sqliteTableSizes.status")] div.options-container-item - span.name Bio: #[span(v-text="sqliteTableSizes.bio")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.bio') }} #[span(v-text="sqliteTableSizes.bio")] div.options-container-item - span.name Avatar: #[span(v-text="sqliteTableSizes.avatar")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.avatar') }} #[span(v-text="sqliteTableSizes.avatar")] div.options-container-item - span.name Online/Offline: #[span(v-text="sqliteTableSizes.onlineOffline")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.online_offline') }} #[span(v-text="sqliteTableSizes.onlineOffline")] div.options-container-item - span.name Friend Log History: #[span(v-text="sqliteTableSizes.friendLogHistory")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.friend_log_history') }} #[span(v-text="sqliteTableSizes.friendLogHistory")] div.options-container-item - span.name Notifications: #[span(v-text="sqliteTableSizes.notification")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.notification') }} #[span(v-text="sqliteTableSizes.notification")] div.options-container-item - span.name Location: #[span(v-text="sqliteTableSizes.location")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.location') }} #[span(v-text="sqliteTableSizes.location")] div.options-container-item - span.name Join/Leave: #[span(v-text="sqliteTableSizes.joinLeave")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.join_leave') }} #[span(v-text="sqliteTableSizes.joinLeave")] div.options-container-item - span.name Portal Spawn: #[span(v-text="sqliteTableSizes.portalSpawn")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.portal_spawn') }} #[span(v-text="sqliteTableSizes.portalSpawn")] div.options-container-item - span.name Video Play: #[span(v-text="sqliteTableSizes.videoPlay")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.video_play') }} #[span(v-text="sqliteTableSizes.videoPlay")] div.options-container-item - span.name Event: #[span(v-text="sqliteTableSizes.event")] + span.name {{ $t('view.settings.advanced.advanced.sqlite_table_size.event') }} #[span(v-text="sqliteTableSizes.event")] //- friends - .x-aside-container(v-show="$refs.menu && $refs.menu.activeIndex !== 'friendsList'" id="aside") + .x-aside-container(v-show="$refs.menu && $refs.menu.activeIndex !== 'friendsList'" id="aside") div(style="display:flex;align-items:baseline") - el-select(v-model="quickSearch" clearable placeholder="Search" filterable remote :remote-method="quickSearchRemoteMethod" popper-class="x-quick-search" @change="quickSearchChange" @visible-change="quickSearchVisibleChange" style="flex:1;padding:10px") + el-select(v-model="quickSearch" clearable :placeholder="$t('side_panel.search_placeholder')" filterable remote :remote-method="quickSearchRemoteMethod" popper-class="x-quick-search" @change="quickSearchChange" @visible-change="quickSearchVisibleChange" style="flex:1;padding:10px") el-option(v-for="item in quickSearchItems" :key="item.value" :value="item.value" :label="item.label") .x-friend-item template(v-if="item.ref") .detail span.name(v-text="item.ref.displayName" :style="{'color':item.ref.$userColour}") - span.extra(v-if="item.ref.state === 'offline'") Offline - span.extra(v-else-if="item.ref.state === 'active'") Active + span.extra(v-if="item.ref.state === 'offline'") {{ $t('side_panel.search_result_offline') }} + span.extra(v-else-if="item.ref.state === 'active'") {{ $t('side_panel.search_result_active') }} location.extra(v-else :location="item.ref.location" :traveling="item.ref.travelingToLocation" :link="false") img.avatar(v-lazy="userImage(item.ref)") - span(v-else) Search More: #[span(v-text="item.label" style="font-weight:bold")] - el-tooltip(placement="bottom" content="Direct access ID/URL from clipboard" :disabled="hideTooltips") + span(v-else) {{ $t('side_panel.search_result_more') }} #[span(v-text="item.label" style="font-weight:bold")] + el-tooltip(placement="bottom" :content="$t('side_panel.direct_access_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="directAccessPaste" size="mini" icon="el-icon-discover" circle) - el-tooltip(placement="bottom" content="Refresh friends" :disabled="hideTooltips") + el-tooltip(placement="bottom" :content="$t('side_panel.refresh_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="API.closeWebSocket(); API.getCurrentUser(); API.refreshFriends()" :loading="API.isRefreshFriendsLoading" size="mini" icon="el-icon-refresh" circle style="margin-right:10px") .x-friend-list(style="padding-bottom:10px") .x-friend-group(style="padding:5px 0 0") - span FRIENDS―{{ onlineFriendCount }}/{{ friends.size }} + span {{ $t('side_panel.friends') }} ― {{ onlineFriendCount }}/{{ friends.size }} .x-friend-group(style="padding:10px 0 5px") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroupMe }") - span.x-link(@click="isFriendsGroupMe = !isFriendsGroupMe" style="margin-left:5px") ME + span.x-link(@click="isFriendsGroupMe = !isFriendsGroupMe" style="margin-left:5px") {{ $t('side_panel.me') }} div(v-show="isFriendsGroupMe") .x-friend-item(:key="API.currentUser.id" @click="showUserDialog(API.currentUser.id)") .avatar(:class="userStatusClass(API.currentUser)") @@ -1515,7 +1515,7 @@ html span.extra(v-else v-text="API.currentUser.statusDescription" :link="false") .x-friend-group(v-show="friendsGroup0.length") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroup0 }") - span.x-link(@click="isFriendsGroup0 = !isFriendsGroup0" style="margin-left:5px") VIP―{{ friendsGroup0.length }} + span.x-link(@click="isFriendsGroup0 = !isFriendsGroup0" style="margin-left:5px") {{ $t('side_panel.favorite') }} ― {{ friendsGroup0.length }} div(v-show="isFriendsGroup0") .x-friend-item(v-for="friend in friendsGroup0" :key="friend.id" @click="showUserDialog(friend.id)") template(v-if="friend.ref") @@ -1524,14 +1524,14 @@ html .detail span.name(v-if="!hideUserMemos && friend.$nickName" :style="{'color':friend.ref.$userColour}") {{ friend.ref.displayName }} ({{ friend.$nickName }}) span.name(v-else v-text="friend.ref.displayName" :style="{'color':friend.ref.$userColour}") - span.extra(v-if="friend.pendingOffline") #[i.el-icon-warning-outline] Pending Offline + span.extra(v-if="friend.pendingOffline") #[i.el-icon-warning-outline] {{ $t('side_panel.penfing_offline') }} location.extra(v-else :location="friend.ref.location" :traveling="friend.ref.travelingToLocation" :link="false") template(v-else) span(v-text="friend.name || friend.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="confirmDeleteFriend(friend.id)" style="margin-left:5px") .x-friend-group(v-show="friendsGroup1.length") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroup1 }") - span.x-link(@click="isFriendsGroup1 = !isFriendsGroup1" style="margin-left:5px") ONLINE―{{ friendsGroup1.length }} + span.x-link(@click="isFriendsGroup1 = !isFriendsGroup1" style="margin-left:5px") {{ $t('side_panel.online') }} ― {{ friendsGroup1.length }} div(v-show="isFriendsGroup1") .x-friend-item(v-for="friend in friendsGroup1" :key="friend.id" @click="showUserDialog(friend.id)") template(v-if="friend.ref") @@ -1540,14 +1540,14 @@ html .detail span.name(v-if="!hideUserMemos && friend.$nickName" :style="{'color':friend.ref.$userColour}") {{ friend.ref.displayName }} ({{ friend.$nickName }}) span.name(v-else v-text="friend.ref.displayName" :style="{'color':friend.ref.$userColour}") - span.extra(v-if="friend.pendingOffline") #[i.el-icon-warning-outline] Pending Offline + span.extra(v-if="friend.pendingOffline") #[i.el-icon-warning-outline] {{ $t('side_panel.penfing_offline') }} location.extra(v-else :location="friend.ref.location" :traveling="friend.ref.travelingToLocation" :link="false") template(v-else) span(v-text="friend.name || friend.id") el-button(type="text" icon="el-icon-close" size="mini" @click.stop="confirmDeleteFriend(friend.id)" style="margin-left:5px") .x-friend-group(v-show="friendsGroup2.length") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroup2 }") - span.x-link(@click="isFriendsGroup2 = !isFriendsGroup2" style="margin-left:5px") ACTIVE―{{ friendsGroup2.length }} + span.x-link(@click="isFriendsGroup2 = !isFriendsGroup2" style="margin-left:5px") {{ $t('side_panel.active') }} ― {{ friendsGroup2.length }} div(v-show="isFriendsGroup2") .x-friend-item(v-for="friend in friendsGroup2" :key="friend.id" @click="showUserDialog(friend.id)") template(v-if="friend.ref") @@ -1562,7 +1562,7 @@ html el-button(type="text" icon="el-icon-close" size="mini" @click.stop="confirmDeleteFriend(friend.id)" style="margin-left:5px") .x-friend-group(v-show="friendsGroup3.length") i.el-icon-arrow-right(:class="{ rotate: isFriendsGroup3 }") - span.x-link(@click="isFriendsGroup3 = !isFriendsGroup3" style="margin-left:5px") OFFLINE―{{ friendsGroup3.length }} + span.x-link(@click="isFriendsGroup3 = !isFriendsGroup3" style="margin-left:5px") {{ $t('side_panel.offline') }} ― {{ friendsGroup3.length }} div(v-show="isFriendsGroup3") .x-friend-item(v-for="friend in friendsGroup3" :key="friend.id" @click="showUserDialog(friend.id)") template(v-if="friend.ref") @@ -1591,18 +1591,18 @@ html div el-tooltip(v-if="userDialog.ref.status" placement="top") template(#content) - span(v-if="userDialog.ref.state === 'active'") Active - span(v-else-if="userDialog.ref.location === 'offline'") Offline - span(v-else-if="userDialog.ref.status === 'active'") Online - span(v-else-if="userDialog.ref.status === 'join me'") Join Me - span(v-else-if="userDialog.ref.status === 'ask me'") Ask Me - span(v-else-if="userDialog.ref.status === 'busy'") Do Not Disturb - span(v-else) Offline + span(v-if="userDialog.ref.state === 'active'") {{ $t('dialog.user.status.active') }} + span(v-else-if="userDialog.ref.location === 'offline'") {{ $t('dialog.user.status.offline') }} + span(v-else-if="userDialog.ref.status === 'active'") {{ $t('dialog.user.status.online') }} + span(v-else-if="userDialog.ref.status === 'join me'") {{ $t('dialog.user.status.join_me') }} + span(v-else-if="userDialog.ref.status === 'ask me'") {{ $t('dialog.user.status.ask_me') }} + span(v-else-if="userDialog.ref.status === 'busy'") {{ $t('dialog.user.status.busy') }} + span(v-else) {{ $t('dialog.user.status.offline') }} i.x-user-status(:class="userStatusClass(userDialog.ref)") template(v-if="userDialog.previousDisplayNames.length > 0") el-tooltip(placement="bottom") template(#content) - span Previous Display Names: + span {{ $t('dialog.user.previous_display_names') }} div(v-for="displayName in userDialog.previousDisplayNames" placement="top") span(v-text="displayName") i.el-icon-caret-bottom @@ -1617,9 +1617,9 @@ html span.flags(:class="languageClass(item.key)" style="display:inline-block;margin-right:5px") div el-tag.name(type="info" effect="plain" size="mini" :class="userDialog.ref.$trustClass" v-text="userDialog.ref.$trustLevel" style="margin-right:5px;margin-top:5px") - el-tag.x-tag-friend(v-if="userDialog.isFriend && userDialog.friend" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Friend No.{{userDialog.friend.no}} + el-tag.x-tag-friend(v-if="userDialog.isFriend && userDialog.friend" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.user.tags.friend_no', { number: userDialog.friend.no }) }} el-tag.x-tag-troll(v-if="userDialog.ref.$isTroll" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Nuisance - el-tag.x-tag-vip(v-if="userDialog.ref.$isModerator" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") VRChat Team + el-tag.x-tag-vip(v-if="userDialog.ref.$isModerator" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.user.tags.vrchat_team') }} el-tag.x-tag-vrcplus(v-if="userDialog.ref.$isVRCPlus" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") VRC+ el-tag.x-tag-platform-pc(v-if="userDialog.ref.last_platform === 'standalonewindows'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") PC el-tag.x-tag-platform-quest(v-else-if="userDialog.ref.last_platform === 'android'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Quest @@ -1631,62 +1631,62 @@ html img.x-link(v-lazy="userDialog.ref.userIcon" style="height:500px" @click="downloadAndSaveImage(userDialog.ref.userIcon)") div(style="flex:none") template(v-if="API.currentUser.id !== userDialog.ref.id") - el-tooltip(v-if="userDialog.isFavorite" placement="top" content="Remove from favorites" :disabled="hideTooltips") + el-tooltip(v-if="userDialog.isFavorite" placement="top" :content="$t('dialog.user.actions.unfavorite_tooltip')" :disabled="hideTooltips") el-button(@click="userDialogCommand('Delete Favorite')" type="warning" icon="el-icon-star-on" circle) - el-tooltip(v-else placement="top" content="Add to favorites" :disabled="hideTooltips") + el-tooltip(v-else placement="top" :content="$t('dialog.user.actions.favorite_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="userDialogCommand('Add Favorite')" icon="el-icon-star-off" circle) el-dropdown(trigger="click" @command="userDialogCommand" size="small") el-button(:type="(userDialog.incomingRequest || userDialog.outgoingRequest || userDialog.isShowAvatar) ? 'success' : (userDialog.isBlock || userDialog.isMute || userDialog.isHideAvatar) ? 'danger' : 'default'" icon="el-icon-more" circle style="margin-left:5px") el-dropdown-menu(#default="dropdown") - el-dropdown-item(icon="el-icon-refresh" command="Refresh") Refresh - el-dropdown-item(icon="el-icon-s-order" command="Copy User") Copy User URL + el-dropdown-item(icon="el-icon-refresh" command="Refresh") {{ $t('dialog.user.actions.refresh') }} + el-dropdown-item(icon="el-icon-s-order" command="Copy User") {{ $t('dialog.user.actions.copy_url') }} template(v-if="userDialog.ref.id === API.currentUser.id") - el-dropdown-item(icon="el-icon-picture-outline" command="Manage Gallery" divided) Manage Gallery/Icons - el-dropdown-item(icon="el-icon-s-custom" command="Show Avatar Author") Show Avatar Author - el-dropdown-item(icon="el-icon-s-custom" command="Show Fallback Avatar Details") Show Fallback Avatar Details - el-dropdown-item(icon="el-icon-edit" command="Edit Social Status" divided) Social Status - el-dropdown-item(icon="el-icon-edit" command="Edit Language") Language - el-dropdown-item(icon="el-icon-edit" command="Edit Bio") Bio - el-dropdown-item(icon="el-icon-switch-button" command="Logout" divided) Logout + el-dropdown-item(icon="el-icon-picture-outline" command="Manage Gallery" divided) {{ $t('dialog.user.actions.manage_gallery_icon') }} + el-dropdown-item(icon="el-icon-s-custom" command="Show Avatar Author") {{ $t('dialog.user.actions.show_avatar_author') }} + el-dropdown-item(icon="el-icon-s-custom" command="Show Fallback Avatar Details") {{ $t('dialog.user.actions.show_fallback_avatar') }} + el-dropdown-item(icon="el-icon-edit" command="Edit Social Status" divided) {{ $t('dialog.user.actions.edit_status') }} + el-dropdown-item(icon="el-icon-edit" command="Edit Language") {{ $t('dialog.user.actions.edit_language') }} + el-dropdown-item(icon="el-icon-edit" command="Edit Bio") {{ $t('dialog.user.actions.edit_bio') }} + el-dropdown-item(icon="el-icon-switch-button" command="Logout" divided) {{ $t('dialog.user.actions.logout') }} template(v-else) template(v-if="userDialog.isFriend") - el-dropdown-item(icon="el-icon-postcard" command="Request Invite" divided) Request Invite - el-dropdown-item(icon="el-icon-postcard" command="Request Invite Message") Request Invite With Message + el-dropdown-item(icon="el-icon-postcard" command="Request Invite" divided) {{ $t('dialog.user.actions.request_invite') }} + el-dropdown-item(icon="el-icon-postcard" command="Request Invite Message") {{ $t('dialog.user.actions.request_invite_with_message') }} template(v-if="lastLocation.location && isGameRunning && checkCanInvite(lastLocation.location)") - el-dropdown-item(icon="el-icon-message" command="Invite") Invite - el-dropdown-item(icon="el-icon-message" command="Invite Message") Invite With Message + el-dropdown-item(icon="el-icon-message" command="Invite") {{ $t('dialog.user.actions.invite') }} + el-dropdown-item(icon="el-icon-message" command="Invite Message") {{ $t('dialog.user.actions.invite_with_message') }} template(v-else-if="userDialog.incomingRequest") - el-dropdown-item(icon="el-icon-check" command="Accept Friend Request") Accept Friend Request - el-dropdown-item(icon="el-icon-close" command="Decline Friend Request") Decline Friend Request - el-dropdown-item(v-else-if="userDialog.outgoingRequest" icon="el-icon-close" command="Cancel Friend Request") Cancel Friend Request - el-dropdown-item(v-else icon="el-icon-plus" command="Send Friend Request") Send Friend Request - el-dropdown-item(icon="el-icon-message" command="Invite To Group") Invite To Group - el-dropdown-item(icon="el-icon-s-custom" command="Show Avatar Author" divided) Show Avatar Author - el-dropdown-item(icon="el-icon-s-custom" command="Show Fallback Avatar Details") Show Fallback Avatar Details - el-dropdown-item(icon="el-icon-tickets" command="Previous Instances") Show Previous Instances - el-dropdown-item(v-if="userDialog.ref.currentAvatarImageUrl" icon="el-icon-picture-outline" command="Previous Images") Show Avatar Previous Images - el-dropdown-item(v-if="userDialog.isBlock" icon="el-icon-circle-check" command="Unblock" divided style="color:#F56C6C") Unblock - el-dropdown-item(v-else icon="el-icon-circle-close" command="Block" divided :disabled="userDialog.ref.$isModerator") Block - el-dropdown-item(v-if="userDialog.isMute" icon="el-icon-microphone" command="Unmute" style="color:#F56C6C") Unmute - el-dropdown-item(v-else icon="el-icon-turn-off-microphone" command="Mute" :disabled="userDialog.ref.$isModerator") Mute - el-dropdown-item(icon="el-icon-user-solid" command="Show Avatar") #[i.el-icon-check.el-icon--left(v-if="userDialog.isShowAvatar")]Show Avatar - el-dropdown-item(icon="el-icon-user" command="Hide Avatar") #[i.el-icon-check.el-icon--left(v-if="userDialog.isHideAvatar")]Hide Avatar - el-dropdown-item(v-if="userDialog.isInteractOff" icon="el-icon-thumb" command="Enable Avatar Interaction" style="color:#F56C6C") Enable Avatar Interaction - el-dropdown-item(v-else icon="el-icon-circle-close" command="Disable Avatar Interaction") Disable Avatar Interaction + el-dropdown-item(icon="el-icon-check" command="Accept Friend Request") {{ $t('dialog.user.actions.accept_friend_request') }} + el-dropdown-item(icon="el-icon-close" command="Decline Friend Request") {{ $t('dialog.user.actions.decline_friend_request') }} + el-dropdown-item(v-else-if="userDialog.outgoingRequest" icon="el-icon-close" command="Cancel Friend Request") {{ $t('dialog.user.actions.cancel_friend_request') }} + el-dropdown-item(v-else icon="el-icon-plus" command="Send Friend Request") {{ $t('dialog.user.actions.send_friend_request') }} + el-dropdown-item(icon="el-icon-message" command="Invite To Group") {{ $t('dialog.user.actions.invite_to_group') }} + el-dropdown-item(icon="el-icon-s-custom" command="Show Avatar Author" divided) {{ $t('dialog.user.actions.show_avatar_author') }} + el-dropdown-item(icon="el-icon-s-custom" command="Show Fallback Avatar Details") {{ $t('dialog.user.actions.show_fallback_avatar') }} + el-dropdown-item(icon="el-icon-tickets" command="Previous Instances") {{ $t('dialog.user.actions.show_previous_instances') }} + el-dropdown-item(v-if="userDialog.ref.currentAvatarImageUrl" icon="el-icon-picture-outline" command="Previous Images") {{ $t('dialog.user.actions.show_previous_images') }} + el-dropdown-item(v-if="userDialog.isBlock" icon="el-icon-circle-check" command="Unblock" divided style="color:#F56C6C") {{ $t('dialog.user.actions.moderation_unblock') }} + el-dropdown-item(v-else icon="el-icon-circle-close" command="Block" divided :disabled="userDialog.ref.$isModerator") {{ $t('dialog.user.actions.moderation_block') }} + el-dropdown-item(v-if="userDialog.isMute" icon="el-icon-microphone" command="Unmute" style="color:#F56C6C") {{ $t('dialog.user.actions.moderation_unmute') }} + el-dropdown-item(v-else icon="el-icon-turn-off-microphone" command="Mute" :disabled="userDialog.ref.$isModerator") {{ $t('dialog.user.actions.moderation_mute') }} + el-dropdown-item(icon="el-icon-user-solid" command="Show Avatar") #[i.el-icon-check.el-icon--left(v-if="userDialog.isShowAvatar")] {{ $t('dialog.user.actions.moderation_show_avatar') }} + el-dropdown-item(icon="el-icon-user" command="Hide Avatar") #[i.el-icon-check.el-icon--left(v-if="userDialog.isHideAvatar")] {{ $t('dialog.user.actions.moderation_hide_avatar') }} + el-dropdown-item(v-if="userDialog.isInteractOff" icon="el-icon-thumb" command="Enable Avatar Interaction" style="color:#F56C6C") {{ $t('dialog.user.actions.moderation_enable_avatar_interaction') }} + el-dropdown-item(v-else icon="el-icon-circle-close" command="Disable Avatar Interaction") {{ $t('dialog.user.actions.moderation_disable_avatar_interaction') }} template(v-if="userDialog.isFriend") - el-dropdown-item(icon="el-icon-delete" command="Unfriend" divided style="color:#F56C6C") Unfriend + el-dropdown-item(icon="el-icon-delete" command="Unfriend" divided style="color:#F56C6C") {{ $t('dialog.user.actions.unfriend') }} el-tabs(ref="userDialogTabs" @tab-click="userDialogTabClick") - el-tab-pane(label="Info") + el-tab-pane(:label="$t('dialog.user.info.header')") template(v-if="isFriendOnline(userDialog.friend) || API.currentUser.id === userDialog.id") div(v-if="userDialog.ref.location" style="display:flex;flex-direction:column;margin-bottom:10px;padding-bottom:10px;border-bottom:1px solid #e4e7ed14") div(style="flex:none") location(:location="userDialog.ref.location" :traveling="userDialog.ref.travelingToLocation") template(v-if="isRealInstance(userDialog.$location.tag)") - el-tooltip(placement="top" content="Launch/Invite" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.user.info.launch_invite_tooltip')" :disabled="hideTooltips") launch(:location="userDialog.$location.tag" style="margin-left:5px") - el-tooltip(placement="top" content="Invite yourself" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.user.info.self_invite_tooltip')" :disabled="hideTooltips") invite-yourself(:location="userDialog.$location.tag" :shortname="userDialog.$location.shortName" style="margin-left:5px") - el-tooltip(placement="top" content="Refresh player count" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.user.info.refresh_user_count_tooltip')" :disabled="hideTooltips") el-button(v-if="userDialog.$location.tag !== lastLocation.location" @click="refreshInstancePlayerCount(userDialog.$location.tag)" size="mini" icon="el-icon-refresh" style="margin-left:5px" circle) span(v-if="userDialog.instance.occupants" style="margin-left:5px") {{ userDialog.instance.occupants }} #[template(v-if="userDialog.instance.friendCount > 0") ({{ userDialog.instance.friendCount }})] .x-friend-list(style="flex:1;margin-top:10px;max-height:150px") @@ -1696,7 +1696,7 @@ html img(v-lazy="userImage(userDialog.$location.user)") .detail span.name(v-text="userDialog.$location.user.displayName" :style="{'color':userDialog.$location.user.$userColour}") - span.extra Instance Creator + span.extra {{ $t('dialog.user.info.instance_creator') }} span(v-else v-text="userDialog.$location.userId") .x-friend-item(v-for="user in userDialog.users" :key="user.id" @click="showUserDialog(user.id)" class="x-friend-item-border") .avatar(:class="userStatusClass(user)") @@ -1711,25 +1711,25 @@ html .x-friend-list(style="max-height:none") .x-friend-item(v-if="!hideUserNotes" style="width:100%;cursor:default") .detail - span.name Note - el-input(v-model="userDialog.note" type="textarea" maxlength="256" show-word-limit :rows="2" :autosize="{ minRows: 1, maxRows: 20 }" @change="checkNote(userDialog.ref, userDialog.note)" @input="cleanNote(userDialog.note)" placeholder="Click to add a note" size="mini" resize="none") + span.name {{ $t('dialog.user.info.note') }} + el-input(v-model="userDialog.note" type="textarea" maxlength="256" show-word-limit :rows="2" :autosize="{ minRows: 1, maxRows: 20 }" @change="checkNote(userDialog.ref, userDialog.note)" @input="cleanNote(userDialog.note)" :placeholder="$t('dialog.user.info.note_placeholder')" size="mini" resize="none") div(style="float:right") i.el-icon-loading(v-if="userDialog.noteSaving" style="margin-left:5px") i.el-icon-more-outline(v-else-if="userDialog.note !== userDialog.ref.note" style="margin-left:5px") el-button(v-if="userDialog.note" type="text" icon="el-icon-delete" size="mini" @click="deleteNote(userDialog.id)" style="margin-left:5px") .x-friend-item(v-if="!hideUserMemos" style="width:100%;cursor:default") .detail - span.name Memo - el-input.extra(v-model="userDialog.memo" type="textarea" :rows="2" :autosize="{ minRows: 1, maxRows: 20 }" placeholder="Click to add a memo" size="mini" resize="none") + span.name {{ $t('dialog.user.info.memo') }} + el-input.extra(v-model="userDialog.memo" type="textarea" :rows="2" :autosize="{ minRows: 1, maxRows: 20 }" :placeholder="$t('dialog.user.info.memo_placeholder')" size="mini" resize="none") .x-friend-item(style="width:100%;cursor:default") .detail - span.name(v-if="userDialog.id !== API.currentUser.id && userDialog.ref.profilePicOverride && userDialog.ref.currentAvatarImageUrl") Avatar Info Last Seen - span.name(v-else) Avatar Info + span.name(v-if="userDialog.id !== API.currentUser.id && userDialog.ref.profilePicOverride && userDialog.ref.currentAvatarImageUrl") {{ $t('dialog.user.info.avatar_info_last_seen') }} + span.name(v-else) {{ $t('dialog.user.info.avatar_info') }} .extra avatar-info(:imageurl="userDialog.ref.currentAvatarImageUrl" :userid="userDialog.id") .x-friend-item(style="width:100%;cursor:default") .detail - span.name Represented Group + span.name {{ $t('dialog.user.info.represented_group') }} .extra(v-if="userDialog.representedGroup.isRepresenting") div(style="display:inline-block;flex:none;margin-right:5px") el-popover(placement="right" width="500px" trigger="click") @@ -1742,7 +1742,7 @@ html .extra(v-else) - .x-friend-item(style="width:100%;cursor:default") .detail - span.name Bio + span.name {{ $t('dialog.user.info.bio') }} pre.extra(style="font-family:inherit;font-size:12px;white-space:pre-wrap;margin:0 0.5em 0 0") {{ userDialog.ref.bio || '-' }} div(v-if="userDialog.id === API.currentUser.id" style="float:right") el-button(type="text" icon="el-icon-edit" size="mini" @click="showBioDialog" style="margin-left:5px") @@ -1754,21 +1754,21 @@ html template(v-if="API.currentUser.id !== userDialog.id") .x-friend-item(style="cursor:default") .detail - span.name Last Seen - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name {{ $t('dialog.user.info.last_seen') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.user.info.accuracy_notice')") i.el-icon-warning span.extra {{ userDialog.lastSeen | formatDate('long') }} .x-friend-item(@click="showPreviousInstancesUserDialog(userDialog.ref)") .detail - span.name Join Count - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name {{ $t('dialog.user.info.join_count') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.user.info.accuracy_notice')") i.el-icon-warning span.extra(v-if="userDialog.joinCount === 0") - span.extra(v-else v-text="userDialog.joinCount") .x-friend-item(style="cursor:default") .detail - span.name Time Together - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name {{ $t('dialog.user.info.time_together') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.user.info.accuracy_notice')") i.el-icon-warning span.extra(v-if="userDialog.timeSpent === 0") - span.extra(v-else) {{ userDialog.timeSpent | timeToText }} @@ -1777,57 +1777,57 @@ html template(#content) span {{ userOnlineForTimestamp(userDialog) | formatDate('short') }} .detail - span.name(v-if="userDialog.ref.state === 'online' && userDialog.ref.$online_for") Online For - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name(v-if="userDialog.ref.state === 'online' && userDialog.ref.$online_for") {{ $t('dialog.user.info.online_for') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.user.info.accuracy_notice')") i.el-icon-warning - span.name(v-else) Offline For - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name(v-else) {{ $t('dialog.user.info.offline_for') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.user.info.accuracy_notice')") i.el-icon-warning span.extra {{ userOnlineFor(userDialog) | timeToText }} .x-friend-item(style="cursor:default") el-tooltip(placement="top") template(#content) - span Last Login {{ userDialog.ref.last_login | formatDate('short') }} + span {{ $t('dialog.user.info.last_login') }} {{ userDialog.ref.last_login | formatDate('short') }} .detail - span.name Last Activity + span.name {{ $t('dialog.user.info.last_activity') }} span.extra {{ userDialog.ref.last_activity | formatDate('long') }} .x-friend-item(style="cursor:default") .detail - span.name Date Joined + span.name {{ $t('dialog.user.info.date_joined') }} span.extra(v-text="userDialog.ref.date_joined") .x-friend-item(v-if="API.currentUser.id !== userDialog.id" style="cursor:default") .detail - span.name(v-if="userDialog.unFriended") Unfriended - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name(v-if="userDialog.unFriended") {{ $t('dialog.user.info.unfriended') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.user.info.accuracy_notice')") i.el-icon-warning - span.name(v-else) Friended - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name(v-else) {{ $t('dialog.user.info.friended') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.user.info.accuracy_notice')") i.el-icon-warning span.extra {{ userDialog.dateFriended | formatDate('long') }} template(v-if="API.currentUser.id === userDialog.id") .x-friend-item(@click="toggleAvatarCopying") .detail - span.name Avatar Cloning - span.extra(v-if="userDialog.ref.allowAvatarCopying" style="color:#67C23A") Allow - span.extra(v-else style="color:#F56C6C") Deny + span.name {{ $t('dialog.user.info.avatar_cloning') }} + span.extra(v-if="userDialog.ref.allowAvatarCopying" style="color:#67C23A") {{ $t('dialog.user.info.avatar_cloning_allow') }} + span.extra(v-else style="color:#F56C6C") {{ $t('dialog.user.info.avatar_cloning_deny') }} template(v-else) .x-friend-item(style="cursor:default") .detail - span.name Avatar Cloning - span.extra(v-if="userDialog.ref.allowAvatarCopying" style="color:#67C23A") Allow - span.extra(v-else style="color:#F56C6C") Deny + span.name {{ $t('dialog.user.info.avatar_cloning') }} + span.extra(v-if="userDialog.ref.allowAvatarCopying" style="color:#67C23A") {{ $t('dialog.user.info.avatar_cloning_allow') }} + span.extra(v-else style="color:#F56C6C") {{ $t('dialog.user.info.avatar_cloning_deny') }} .x-friend-item(v-if="userDialog.ref.id === API.currentUser.id && API.currentUser.homeLocation" @click="showWorldDialog(API.currentUser.homeLocation)" style="width:100%") .detail - span.name Home Location + span.name {{ $t('dialog.user.info.home_location') }} span.extra span(v-text="userDialog.$homeLocationName") el-button(@click.stop="resetHome()" size="mini" icon="el-icon-delete" circle style="margin-left:5px") - el-tab-pane(label="Groups") + el-tab-pane(:label="$t('dialog.user.groups.header')") el-button(type="default" :loading="userDialog.isGroupsLoading" @click="getUserGroups(userDialog.id)" size="mini" icon="el-icon-refresh" circle) - span(style="margin-left:5px") Total {{ userGroups.groups.length }} + span(style="margin-left:5px") {{ $t('dialog.user.groups.total_count', { count: userGroups.groups.length }) }} div(v-loading="userDialog.isGroupsLoading" style="margin-top:10px") template(v-if="userGroups.ownGroups.length > 0") - span(style="font-weight:bold;font-size:16px") Own Groups + span(style="font-weight:bold;font-size:16px") {{ $t('dialog.user.groups.own_groups') }} span(style="color:#909399;font-size:12px;margin-left:5px") {{ userGroups.ownGroups.length }} .x-friend-list(style="margin-top:10px;margin-bottom:15px;min-height:60px") .x-friend-item(v-for="group in userGroups.ownGroups" :key="group.id" @click="showGroupDialog(group.id)" class="x-friend-item-border") @@ -1837,7 +1837,7 @@ html span.name(v-text="group.name") span.extra ({{ group.memberCount }}) template(v-if="userGroups.mutualGroups.length > 0") - span(style="font-weight:bold;font-size:16px") Mutual Groups + span(style="font-weight:bold;font-size:16px") {{ $t('dialog.user.groups.mutual_groups') }} span(style="color:#909399;font-size:12px;margin-left:5px") {{ userGroups.mutualGroups.length }} .x-friend-list(style="margin-top:10px;margin-bottom:15px;min-height:60px") .x-friend-item(v-for="group in userGroups.mutualGroups" :key="group.id" @click="showGroupDialog(group.id)" class="x-friend-item-border") @@ -1847,7 +1847,7 @@ html span.name(v-text="group.name") span.extra ({{ group.memberCount }}) template(v-if="userGroups.remainingGroups.length > 0") - span(style="font-weight:bold;font-size:16px") Groups + span(style="font-weight:bold;font-size:16px") {{ $t('dialog.user.groups.groups') }} span(style="color:#909399;font-size:12px;margin-left:5px") {{ userGroups.remainingGroups.length }} .x-friend-list(style="margin-top:10px;margin-bottom:15px;min-height:60px") .x-friend-item(v-for="group in userGroups.remainingGroups" :key="group.id" @click="showGroupDialog(group.id)" class="x-friend-item-border") @@ -1856,12 +1856,12 @@ html .detail span.name(v-text="group.name") span.extra ({{ group.memberCount }}) - el-tab-pane(label="Worlds") + el-tab-pane(:label="$t('dialog.user.worlds.header')") el-button(type="default" :loading="userDialog.isWorldsLoading" @click="refreshUserDialogWorlds()" size="mini" icon="el-icon-refresh" circle) - span(style="margin-left:5px") Total {{ userDialog.worlds.length }} + span(style="margin-left:5px") {{ $t('dialog.user.worlds.total_count', { count: userDialog.worlds.length }) }} el-radio-group(v-model="userDialog.worldSorting" size="mini" style="margin-left:30px" @change="changeUserDialogWorldSorting") - el-radio(label="name") by name - el-radio(label="update") by update + el-radio(label="name") {{ $t('dialog.user.worlds.sort_by_name') }} + el-radio(label="update") {{ $t('dialog.user.worlds.sort_by_update') }} .x-friend-list(v-loading="userDialog.isWorldsLoading" style="margin-top:10px;min-height:60px") .x-friend-item(v-for="world in userDialog.worlds" :key="world.id" @click="showWorldDialog(world.id)" class="x-friend-item-border") .avatar @@ -1869,7 +1869,7 @@ html .detail span.name(v-text="world.name") span.extra(v-if="world.occupants") ({{ world.occupants }}) - el-tab-pane(label="Favorite Worlds") + el-tab-pane(:label="$t('dialog.user.favorite_worlds.header')") el-button(type="default" :loading="userDialog.isFavoriteWorldsLoading" @click="getUserFavoriteWorlds(userDialog.id)" size="mini" icon="el-icon-refresh" circle) el-tabs(type="card" v-loading="userDialog.isFavoriteWorldsLoading" style="margin-top:10px") template(v-for="(list, index) in userFavoriteWorlds" v-if="list") @@ -1885,17 +1885,17 @@ html .detail span.name(v-text="world.name") span.extra(v-if="world.occupants") ({{ world.occupants }}) - el-tab-pane(label="Avatars") + el-tab-pane(:label="$t('dialog.user.avatars.header')") template(v-if="userDialog.ref.id === API.currentUser.id") el-button(type="default" :loading="userDialog.isAvatarsLoading" @click="refreshUserDialogAvatars()" size="mini" icon="el-icon-refresh" circle) - span(style="margin-left:5px") Total {{ userDialogAvatars.length }} + span(style="margin-left:5px") {{ $t('dialog.user.avatars.total_count', { count: userDialogAvatars.length }) }} el-radio-group(v-if="userDialog.ref.id === API.currentUser.id" v-model="userDialog.avatarSorting" size="mini" style="margin-left:30px;margin-right:30px" @change="changeUserDialogAvatarSorting") - el-radio(label="name") by name - el-radio(label="update") by update + el-radio(label="name") {{ $t('dialog.user.avatars.sort_by_name') }} + el-radio(label="update") {{ $t('dialog.user.avatars.sort_by_update') }} el-radio-group(v-if="userDialog.ref.id === API.currentUser.id" v-model="userDialog.avatarReleaseStatus" size="mini" style="margin-left:30px") - el-radio(label="all") all - el-radio(label="public") public - el-radio(label="private") private + el-radio(label="all") {{ $t('dialog.user.avatars.all') }} + el-radio(label="public") {{ $t('dialog.user.avatars.public') }} + el-radio(label="private") {{ $t('dialog.user.avatars.private') }} .x-friend-list(style="margin-top:10px;min-height:60px") .x-friend-item(v-for="avatar in userDialogAvatars" @click="showAvatarDialog(avatar.id)" class="x-friend-item-border") .avatar @@ -1905,7 +1905,7 @@ html span.extra(v-text="avatar.releaseStatus" v-if="avatar.releaseStatus === 'public'" style="color: #67c23a;") span.extra(v-text="avatar.releaseStatus" v-else-if="avatar.releaseStatus === 'private'" style="color: #f56c6c;") span.extra(v-text="avatar.releaseStatus" v-else) - el-tab-pane(label="JSON") + el-tab-pane(:label="$t('dialog.user.json.header')") el-button(type="default" @click="refreshUserDialogTreeData()" size="mini" icon="el-icon-refresh" circle) el-tree(:data="userDialog.treeData" style="margin-top:5px;font-size:12px") template(#default="scope") @@ -1928,57 +1928,57 @@ html div(style="margin-top:5px") span.x-link(v-text="worldDialog.ref.authorName" @click="showUserDialog(worldDialog.ref.authorId)" style="color:#909399;font-family:monospace") div - el-tag(v-if="worldDialog.ref.$isLabs" type="primary" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Labs - el-tag(v-else-if="worldDialog.ref.releaseStatus === 'public'" type="success" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Public - el-tag(v-else type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Private + el-tag(v-if="worldDialog.ref.$isLabs" type="primary" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.world.tags.labs') }} + el-tag(v-else-if="worldDialog.ref.releaseStatus === 'public'" type="success" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.world.tags.public') }} + el-tag(v-else type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.world.tags.private') }} el-tag.x-tag-platform-pc(v-if="worldDialog.isPC" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") PC el-tag.x-tag-platform-quest(v-if="worldDialog.isQuest" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Quest el-tag(type="info" effect="plain" size="mini" v-text="worldDialog.fileSize" style="margin-right:5px;margin-top:5px") el-tag(v-if="worldDialog.inCache" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") span(v-text="worldDialog.cacheSize") - | Cache + | {{ $t('dialog.world.tags.cache')}} div(style="margin-top:5px") span(v-show="worldDialog.ref.name !== worldDialog.ref.description" v-text="worldDialog.ref.description" style="font-size:12px") div(style="flex:none;margin-left:10px") - el-tooltip(v-if="worldDialog.inCache" placement="top" content="Delete world from cache" :disabled="hideTooltips") + el-tooltip(v-if="worldDialog.inCache" placement="top" :content="$t('dialog.world.actions.delete_cache_tooltip')" :disabled="hideTooltips") el-button(icon="el-icon-delete" circle @click="deleteVRChatCache(worldDialog.ref)" :disabled="isGameRunning && worldDialog.cacheLocked") - el-tooltip(v-if="worldDialog.isFavorite" placement="top" content="Favorite/Unfavorite" :disabled="hideTooltips") + el-tooltip(v-if="worldDialog.isFavorite" placement="top" :content="$t('dialog.world.actions.unfavorite_tooltip')" :disabled="hideTooltips") el-button(type="default" icon="el-icon-star-on" circle @click="worldDialogCommand('Add Favorite')" style="margin-left:5px") - el-tooltip(v-else placement="top" content="Favorite/Unfavorite" :disabled="hideTooltips") + el-tooltip(v-else placement="top" :content="$t('dialog.world.actions.favorite_tooltip')" :disabled="hideTooltips") el-button(type="default" icon="el-icon-star-off" circle @click="worldDialogCommand('Add Favorite')" style="margin-left:5px") el-dropdown(trigger="click" @command="worldDialogCommand" size="small" style="margin-left:5px") el-button(type="default" icon="el-icon-more" circle) el-dropdown-menu(#default="dropdown") - el-dropdown-item(icon="el-icon-refresh" command="Refresh") Refresh - el-dropdown-item(icon="el-icon-s-flag" command="New Instance" divided) New Instance - el-dropdown-item(v-if="API.currentUser.$homeLocation && API.currentUser.$homeLocation.worldId === worldDialog.id" icon="el-icon-magic-stick" command="Reset Home" divided) Reset Home - el-dropdown-item(v-else icon="el-icon-s-home" command="Make Home" divided) Make Home - el-dropdown-item(icon="el-icon-tickets" command="Previous Instances") Show Previous Instances + el-dropdown-item(icon="el-icon-refresh" command="Refresh") {{ $t('dialog.world.actions.refresh') }} + el-dropdown-item(icon="el-icon-s-flag" command="New Instance" divided) {{ $t('dialog.world.actions.new_instance') }} + el-dropdown-item(v-if="API.currentUser.$homeLocation && API.currentUser.$homeLocation.worldId === worldDialog.id" icon="el-icon-magic-stick" command="Reset Home" divided) {{ $t('dialog.world.actions.reset_home') }} + el-dropdown-item(v-else icon="el-icon-s-home" command="Make Home" divided) {{ $t('dialog.world.actions.make_home') }} + el-dropdown-item(icon="el-icon-tickets" command="Previous Instances") {{ $t('dialog.world.actions.show_previous_instances') }} template(v-if="API.currentUser.id !== worldDialog.ref.authorId") - el-dropdown-item(icon="el-icon-picture-outline" command="Previous Images") Show Previous Images + el-dropdown-item(icon="el-icon-picture-outline" command="Previous Images") {{ $t('dialog.world.actions.show_previous_images') }} template(v-else) - el-dropdown-item(icon="el-icon-edit" command="Rename") Rename - el-dropdown-item(icon="el-icon-edit" command="Change Description") Change Description - el-dropdown-item(icon="el-icon-edit" command="Change Capacity") Change Capacity - el-dropdown-item(icon="el-icon-edit" command="Change YouTube Preview") Change YouTube Preview - el-dropdown-item(icon="el-icon-edit" command="Change Tags") Change Tags - el-dropdown-item(icon="el-icon-picture-outline" command="Change Image") Change Image - el-dropdown-item(v-if="worldDialog.ref.unityPackageUrl" icon="el-icon-download" command="Download Unity Package") Download Unity Package - el-dropdown-item(v-if="worldDialog.ref.tags.includes('system_approved') || worldDialog.ref.tags.includes('system_labs')" icon="el-icon-view" command="Unpublish" divided) Unpublish - el-dropdown-item(v-else icon="el-icon-view" command="Publish" divided) Publish To Labs - el-dropdown-item(icon="el-icon-delete" command="Delete" style="color:#F56C6C") Delete + el-dropdown-item(icon="el-icon-edit" command="Rename") {{ $t('dialog.world.actions.rename') }} + el-dropdown-item(icon="el-icon-edit" command="Change Description") {{ $t('dialog.world.actions.change_description') }} + el-dropdown-item(icon="el-icon-edit" command="Change Capacity") {{ $t('dialog.world.actions.change_capacity') }} + el-dropdown-item(icon="el-icon-edit" command="Change YouTube Preview") {{ $t('dialog.world.actions.change_preview') }} + el-dropdown-item(icon="el-icon-edit" command="Change Tags") {{ $t('dialog.world.actions.change_tags') }} + el-dropdown-item(icon="el-icon-picture-outline" command="Change Image") {{ $t('dialog.world.actions.change_image') }} + el-dropdown-item(v-if="worldDialog.ref.unityPackageUrl" icon="el-icon-download" command="Download Unity Package") {{ $t('dialog.world.actions.download_package') }} + el-dropdown-item(v-if="worldDialog.ref.tags.includes('system_approved') || worldDialog.ref.tags.includes('system_labs')" icon="el-icon-view" command="Unpublish" divided) {{ $t('dialog.world.actions.unpublish') }} + el-dropdown-item(v-else icon="el-icon-view" command="Publish" divided) {{ $t('dialog.world.actions.publish_to_labs') }} + el-dropdown-item(icon="el-icon-delete" command="Delete" style="color:#F56C6C") {{ $t('dialog.world.actions.delete') }} el-tabs - el-tab-pane(label="Instances") + el-tab-pane(:label="$t('dialog.world.instances.header')") div. - #[i.el-icon-user] Public {{ worldDialog.ref.publicOccupants | commaNumber }} - #[i.el-icon-user-solid(style="margin-left:10px")] Private {{ worldDialog.ref.privateOccupants | commaNumber }} - #[i.el-icon-check(style="margin-left:10px")] Capacity {{ worldDialog.ref.capacity | commaNumber }} ({{ worldDialog.ref.capacity * 2 | commaNumber }}) + #[i.el-icon-user] {{ $t('dialog.world.instances.public_count', { count: worldDialog.ref.publicOccupants }) }} + #[i.el-icon-user-solid(style="margin-left:10px")] {{ $t('dialog.world.instances.private_count', { count: worldDialog.ref.privateOccupants }) }} + #[i.el-icon-check(style="margin-left:10px")] {{ $t('dialog.world.instances.capacity_count', { count: worldDialog.ref.capacity, max: worldDialog.ref.capacity * 2 }) }} div(v-for="room in worldDialog.rooms" :key="room.id") div(style="margin:5px 0") location-world(:locationobject="room.$location" :currentuserid="API.currentUser.id" :worlddialogshortname="worldDialog.$location.shortName") - el-tooltip(placement="top" content="Invite yourself" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.world.instances.self_invite_tooltip')" :disabled="hideTooltips") invite-yourself(:location="room.$location.tag" :shortname="room.$location.shortName" style="margin-left:5px") - el-tooltip(placement="top" content="Refresh player count" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.world.instances.refresh_user_count_tooltip')" :disabled="hideTooltips") el-button(v-if="room.$location.tag !== lastLocation.location" @click="refreshInstancePlayerCount(room.$location.tag)" size="mini" icon="el-icon-refresh" style="margin-left:5px" circle) span(v-if="room.occupants" style="margin-left:5px") {{ room.occupants }} #[template(v-if="room.friendCount > 0") ({{ room.friendCount }})] .x-friend-list(style="margin:10px 0;max-height:unset" v-if="room.$location.userId || room.users.length") @@ -1988,7 +1988,7 @@ html img(v-lazy="userImage(room.$location.user)") .detail span.name(v-text="room.$location.user.displayName" :style="{'color':room.$location.user.$userColour}") - span.extra Instance Creator + span.extra {{ $t('dialog.world.instances.instance_creator') }} span(v-else v-text="room.$location.userId") .x-friend-item(v-for="user in room.users" :key="user.id" @click="showUserDialog(user.id)" class="x-friend-item-border") .avatar(:class="userStatusClass(user)") @@ -2000,84 +2000,84 @@ html timer(:epoch="user.$travelingToTime") span.extra(v-else) timer(:epoch="user.$location_at") - el-tab-pane(label="Info") + el-tab-pane(:label="$t('dialog.world.info.header')") .x-friend-list(style="max-height:none") div(style="width:100%;display:flex") .x-friend-item(style="width:350px;cursor:default") .detail - span.name World ID + span.name {{ $t('dialog.world.info.id') }} span.extra {{ worldDialog.id }} - el-tooltip(placement="top" content="Copy to clipboard" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.world.info.id_tooltip')" :disabled="hideTooltips") el-dropdown(trigger="click" @click.native.stop size="mini" style="margin-left:5px") el-button(type="default" icon="el-icon-s-order" size="mini" circle) el-dropdown-menu(#default="dropdown") - el-dropdown-item(@click.native="copyWorldId(worldDialog.id)") Copy ID - el-dropdown-item(@click.native="copyWorldUrl(worldDialog.id)") Copy URL + el-dropdown-item(@click.native="copyWorldId(worldDialog.id)") {{ $t('dialog.world.info.copy_id') }} + el-dropdown-item(@click.native="copyWorldUrl(worldDialog.id)") {{ $t('dialog.world.info.copy_url') }} .x-friend-item(v-if="worldDialog.ref.previewYoutubeId" style="width:350px" @click="openExternalLink(`https://www.youtube.com/watch?v=${worldDialog.ref.previewYoutubeId}`)") .detail - span.name YouTube Preview + span.name {{ $t('dialog.world.info.youtube_preview') }} span.extra https://www.youtube.com/watch?v={{ worldDialog.ref.previewYoutubeId }} .x-friend-item(style="cursor:default") .detail - span.name Players + span.name {{ $t('dialog.world.info.players') }} span.extra {{ worldDialog.ref.occupants | commaNumber }} .x-friend-item(style="cursor:default") .detail - span.name Favorites + span.name {{ $t('dialog.world.info.favorites') }} span.extra {{ worldDialog.ref.favorites | commaNumber }} | #[template(v-if="worldDialog.ref.favorites > 0 && worldDialog.ref.visits > 0") ({{ Math.round(((worldDialog.ref.favorites - worldDialog.ref.visits) / worldDialog.ref.visits * 100 + 100) * 100) / 100 }}%)] .x-friend-item(style="cursor:default") .detail - span.name Visits + span.name {{ $t('dialog.world.info.visits') }} span.extra {{ worldDialog.ref.visits | commaNumber }} .x-friend-item(style="cursor:default") .detail - span.name Capacity + span.name {{ $t('dialog.world.info.capacity') }} span.extra {{ worldDialog.ref.capacity | commaNumber }} ({{ worldDialog.ref.capacity * 2 | commaNumber }}) .x-friend-item(style="cursor:default") .detail - span.name Heat + span.name {{ $t('dialog.world.info.heat') }} span.extra {{ worldDialog.ref.heat | commaNumber }} {{ '🔥'.repeat(worldDialog.ref.heat) }} .x-friend-item(style="cursor:default") .detail - span.name Popularity + span.name {{ $t('dialog.world.info.popularity') }} span.extra {{ worldDialog.ref.popularity | commaNumber }} {{ '💖'.repeat(worldDialog.ref.popularity) }} .x-friend-item(style="cursor:default") .detail - span.name Created + span.name {{ $t('dialog.world.info.created_at') }} span.extra {{ worldDialog.ref.created_at | formatDate('long') }} .x-friend-item(style="cursor:default") .detail - span.name Last Updated + span.name {{ $t('dialog.world.info.last_updated') }} span.extra {{ worldDialog.fileCreatedAt | formatDate('long') }} .x-friend-item(style="cursor:default") .detail - span.name Version + span.name {{ $t('dialog.world.info.version') }} span.extra(v-text="worldDialog.ref.version") .x-friend-item(style="width:525px;cursor:default") .detail - span.name Platform + span.name {{ $t('dialog.world.info.platform') }} span.extra(v-text="worldDialogPlatform") .x-friend-item(style="cursor:default") .detail - span.name Last Visit - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name {{ $t('dialog.world.info.last_visited') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.world.info.accuracy_notice')") i.el-icon-warning span.extra {{ worldDialog.lastVisit | formatDate('long') }} .x-friend-item(@click="showPreviousInstancesWorldDialog(worldDialog.ref)") .detail - span.name Visit Count - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name {{ $t('dialog.world.info.visit_count') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.world.info.accuracy_notice')") i.el-icon-warning span.extra(v-text="worldDialog.visitCount") .x-friend-item(style="cursor:default") .detail - span.name Time Spent - el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" content="Info from local database may not be accurate") + span.name {{ $t('dialog.world.info.time_spent') }} + el-tooltip(v-if="!hideTooltips" placement="top" style="margin-left:5px" :content="$t('dialog.world.info.accuracy_notice')") i.el-icon-warning span.extra(v-if="worldDialog.timeSpent === 0") - span.extra(v-else) {{ worldDialog.timeSpent | timeToText }} - el-tab-pane(label="JSON") + el-tab-pane(:label="$t('dialog.world.json.header')") el-button(type="default" @click="refreshWorldDialogTreeData()" size="mini" icon="el-icon-refresh" circle) el-tree(:data="worldDialog.treeData" style="margin-top:5px;font-size:12px") template(#default="scope") @@ -2099,71 +2099,71 @@ html div(style="margin-top:5px") span.x-link(v-text="avatarDialog.ref.authorName" @click="showUserDialog(avatarDialog.ref.authorId)" style="color:#909399;font-family:monospace") div(style="margin-top:5px") - el-tag(v-if="avatarDialog.ref.releaseStatus === 'public'" type="success" effect="plain" size="mini" style="margin-right:5px") Public - el-tag(v-else type="danger" effect="plain" size="mini" style="margin-right:5px") Private - el-tag(v-if="avatarDialog.isQuestFallback" type="info" effect="plain" size="mini" style="margin-right:5px") Fallback + el-tag(v-if="avatarDialog.ref.releaseStatus === 'public'" type="success" effect="plain" size="mini" style="margin-right:5px") {{ $t('dialog.avatar.tags.public') }} + el-tag(v-else type="danger" effect="plain" size="mini" style="margin-right:5px") {{ $t('dialog.avatar.tags.private') }} + el-tag(v-if="avatarDialog.isQuestFallback" type="info" effect="plain" size="mini" style="margin-right:5px") {{ $t('dialog.avatar.tags.fallback') }} el-tag(v-if="avatarDialog.fileSize" type="info" effect="plain" size="mini" v-text="avatarDialog.fileSize" style="margin-right:5px") el-tag(v-if="avatarDialog.inCache" type="info" effect="plain" size="mini") span(v-text="avatarDialog.cacheSize") - | Cache + | {{ $t('dialog.avatar.tags.cache') }} div(style="margin-top:5px") span(v-show="avatarDialog.ref.name !== avatarDialog.ref.description" v-text="avatarDialog.ref.description" style="font-size:12px") div(style="flex:none;margin-left:10px") - el-tooltip(v-if="avatarDialog.inCache" placement="top" content="Delete avatar from cache" :disabled="hideTooltips") + el-tooltip(v-if="avatarDialog.inCache" placement="top" :content="$t('dialog.avatar.actions.delete_cache_tooltip')" :disabled="hideTooltips") el-button(icon="el-icon-delete" circle @click="deleteVRChatCache(avatarDialog.ref)" :disabled="isGameRunning && avatarDialog.cacheLocked") - el-tooltip(v-if="avatarDialog.isFavorite" placement="top" content="Remove from favorites" :disabled="hideTooltips") + el-tooltip(v-if="avatarDialog.isFavorite" placement="top" :content="$t('dialog.avatar.actions.unfavorite_tooltip')" :disabled="hideTooltips") el-button(type="warning" icon="el-icon-star-on" circle @click="avatarDialogCommand('Delete Favorite')" style="margin-left:5px") - el-tooltip(v-else placement="top" content="Add to favorites" :disabled="hideTooltips") + el-tooltip(v-else placement="top" :content="$t('dialog.avatar.actions.favorite_tooltip')" :disabled="hideTooltips") el-button(type="default" icon="el-icon-star-off" circle @click="avatarDialogCommand('Add Favorite')" style="margin-left:5px") el-dropdown(trigger="click" @command="avatarDialogCommand" size="small" style="margin-left:5px") el-button(:type="avatarDialog.isBlocked ? 'danger' : 'default'" icon="el-icon-more" circle style="margin-left:5px") el-dropdown-menu(#default="dropdown") - el-dropdown-item(icon="el-icon-refresh" command="Refresh") Refresh - el-dropdown-item(icon="el-icon-check" command="Select Avatar") Select Avatar - el-dropdown-item(v-if="/quest/.test(avatarDialog.ref.tags)" icon="el-icon-check" command="Select Fallback Avatar") Select Fallback Avatar - el-dropdown-item(v-if="avatarDialog.isBlocked" icon="el-icon-circle-check" command="Unblock Avatar" style="color:#F56C6C") Unblock Avatar - el-dropdown-item(v-else icon="el-icon-circle-close" command="Block Avatar") Block Avatar - el-dropdown-item(v-if="avatarDialog.ref.authorId !== API.currentUser.id" icon="el-icon-picture-outline" command="Previous Images") Previous Images + el-dropdown-item(icon="el-icon-refresh" command="Refresh") {{ $t('dialog.avatar.actions.refresh') }} + el-dropdown-item(icon="el-icon-check" command="Select Avatar") {{ $t('dialog.avatar.actions.select') }} + el-dropdown-item(v-if="/quest/.test(avatarDialog.ref.tags)" icon="el-icon-check" command="Select Fallback Avatar") {{ $t('dialog.avatar.actions.select_fallback') }} + el-dropdown-item(v-if="avatarDialog.isBlocked" icon="el-icon-circle-check" command="Unblock Avatar" style="color:#F56C6C") {{ $t('dialog.avatar.actions.unblock') }} + el-dropdown-item(v-else icon="el-icon-circle-close" command="Block Avatar") {{ $t('dialog.avatar.actions.block') }} + el-dropdown-item(v-if="avatarDialog.ref.authorId !== API.currentUser.id" icon="el-icon-picture-outline" command="Previous Images") {{ $t('dialog.avatar.actions.show_previous_images') }} template(v-if="avatarDialog.ref.authorId === API.currentUser.id") - el-dropdown-item(v-if="avatarDialog.ref.releaseStatus === 'public'" icon="el-icon-user-solid" command="Make Private" divided) Make Private - el-dropdown-item(v-else icon="el-icon-user" command="Make Public" divided) Make Public - el-dropdown-item(icon="el-icon-edit" command="Rename") Rename - el-dropdown-item(icon="el-icon-edit" command="Change Description") Change Description - el-dropdown-item(icon="el-icon-picture-outline" command="Change Image") Change Image - el-dropdown-item(v-if="avatarDialog.ref.unityPackageUrl" icon="el-icon-download" command="Download Unity Package") Download Unity Package - el-dropdown-item(icon="el-icon-user" command="Delete" style="color:#F56C6C" divided) Delete + el-dropdown-item(v-if="avatarDialog.ref.releaseStatus === 'public'" icon="el-icon-user-solid" command="Make Private" divided) {{ $t('dialog.avatar.actions.make_private') }} + el-dropdown-item(v-else icon="el-icon-user" command="Make Public" divided) {{ $t('dialog.avatar.actions.make_public') }} + el-dropdown-item(icon="el-icon-edit" command="Rename") {{ $t('dialog.avatar.actions.rename') }} + el-dropdown-item(icon="el-icon-edit" command="Change Description") {{ $t('dialog.avatar.actions.change_description') }} + el-dropdown-item(icon="el-icon-picture-outline" command="Change Image") {{ $t('dialog.avatar.actions.change_image') }} + el-dropdown-item(v-if="avatarDialog.ref.unityPackageUrl" icon="el-icon-download" command="Download Unity Package") {{ $t('dialog.avatar.actions.download_package') }} + el-dropdown-item(icon="el-icon-user" command="Delete" style="color:#F56C6C" divided) {{ $t('dialog.avatar.actions.delete') }} el-tabs - el-tab-pane(label="Info") + el-tab-pane(:label="$t('dialog.avatar.info.header')") .x-friend-list .x-friend-item(style="width:100%;cursor:default") .detail - span.name Avatar ID + span.name {{ $t('dialog.avatar.info.id') }} span.extra {{ avatarDialog.id }} - el-tooltip(placement="top" content="Copy to clipboard" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.avatar.info.id_tooltip')" :disabled="hideTooltips") el-dropdown(trigger="click" @click.native.stop size="mini" style="margin-left:5px") el-button(type="default" icon="el-icon-s-order" size="mini" circle) el-dropdown-menu(#default="dropdown") - el-dropdown-item(@click.native="copyAvatarId(avatarDialog.id)") Copy ID - el-dropdown-item(@click.native="copyAvatarUrl(avatarDialog.id)") Copy URL + el-dropdown-item(@click.native="copyAvatarId(avatarDialog.id)") {{ $t('dialog.avatar.info.copy_id') }} + el-dropdown-item(@click.native="copyAvatarUrl(avatarDialog.id)") {{ $t('dialog.avatar.info.copy_url') }} .x-friend-item(style="cursor:default") .detail - span.name Created + span.name {{ $t('dialog.avatar.info.created_at') }} span.extra {{ avatarDialog.ref.created_at | formatDate('long') }} .x-friend-item(style="cursor:default") .detail - span.name Last Updated + span.name {{ $t('dialog.avatar.info.last_updated') }} span.extra {{ avatarDialog.ref.updated_at | formatDate('long') }} .x-friend-item(style="cursor:default") .detail - span.name Version + span.name {{ $t('dialog.avatar.info.version') }} span.extra(v-if="avatarDialog.ref.version !== 0" v-text="avatarDialog.ref.version") span.extra(v-else) - .x-friend-item(style="width:100%;cursor:default") .detail - span.name Platform + span.name {{ $t('dialog.avatar.info.platform') }} span.extra(v-if="avatarDialogPlatform" v-text="avatarDialogPlatform") span.extra(v-else) - - el-tab-pane(label="JSON") + el-tab-pane(:label="$t('dialog.avatar.json.header')") el-button(type="default" @click="refreshAvatarDialogTreeData()" size="mini" icon="el-icon-refresh" circle) el-tree(:data="avatarDialog.treeData" style="margin-top:5px;font-size:12px") template(#default="scope") @@ -2194,66 +2194,66 @@ html div(style="margin-top:5px") span.x-link(v-text="groupDialog.ownerDisplayName" @click="showUserDialog(groupDialog.ref.ownerId)" style="color:#909399;font-family:monospace") .group-tags - el-tag(v-if="groupDialog.ref.isVerified" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Verified + el-tag(v-if="groupDialog.ref.isVerified" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.verified') }} - el-tag(v-if="groupDialog.ref.privacy === 'private'" type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Private - el-tag(v-if="groupDialog.ref.privacy === 'default'" type="success" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Public + el-tag(v-if="groupDialog.ref.privacy === 'private'" type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.private') }} + el-tag(v-if="groupDialog.ref.privacy === 'default'" type="success" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.public') }} - el-tag(v-if="groupDialog.ref.joinState === 'open'" type="success" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Open - el-tag(v-else-if="groupDialog.ref.joinState === 'request'" type="warning" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Request - el-tag(v-else-if="groupDialog.ref.joinState === 'invite'" type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Invite - el-tag(v-else-if="groupDialog.ref.joinState === 'closed'" type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Closed + el-tag(v-if="groupDialog.ref.joinState === 'open'" type="success" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.open') }} + el-tag(v-else-if="groupDialog.ref.joinState === 'request'" type="warning" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.request') }} + el-tag(v-else-if="groupDialog.ref.joinState === 'invite'" type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.invite') }} + el-tag(v-else-if="groupDialog.ref.joinState === 'closed'" type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.closed') }} - el-tag(v-if="groupDialog.inGroup" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Joined - el-tag(v-if="groupDialog.ref.myMember && groupDialog.ref.myMember.bannedAt" type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Banned + el-tag(v-if="groupDialog.inGroup" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.joined') }} + el-tag(v-if="groupDialog.ref.myMember && groupDialog.ref.myMember.bannedAt" type="danger" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.banned') }} template(v-if="groupDialog.inGroup && groupDialog.ref.myMember") - el-tag(v-if="groupDialog.ref.myMember.visibility === 'visible'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Visible - el-tag(v-else-if="groupDialog.ref.myMember.visibility === 'friends'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Friends - el-tag(v-else-if="groupDialog.ref.myMember.visibility === 'hidden'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Hidden - el-tag(v-if="groupDialog.ref.myMember.isSubscribedToAnnouncements" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") Subscribed + el-tag(v-if="groupDialog.ref.myMember.visibility === 'visible'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.visible') }} + el-tag(v-else-if="groupDialog.ref.myMember.visibility === 'friends'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.friends') }} + el-tag(v-else-if="groupDialog.ref.myMember.visibility === 'hidden'" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.hidden') }} + el-tag(v-if="groupDialog.ref.myMember.isSubscribedToAnnouncements" type="info" effect="plain" size="mini" style="margin-right:5px;margin-top:5px") {{ $t('dialog.group.tags.subscribed') }} .group-description(style="margin-top:5px") span(v-show="groupDialog.ref.name !== groupDialog.ref.description" v-text="groupDialog.ref.description" style="font-size:12px") div(style="flex:none;margin-left:10px") template(v-if="groupDialog.inGroup") - el-tooltip(v-if="groupDialog.ref.isRepresenting" placement="top" content="Stop Representing" :disabled="hideTooltips") + el-tooltip(v-if="groupDialog.ref.isRepresenting" placement="top" :content="$t('dialog.group.actions.unrepresent_tooltip')" :disabled="hideTooltips") el-button(type="warning" icon="el-icon-star-on" circle @click="clearGroupRepresentation(groupDialog.id)" style="margin-left:5px") - el-tooltip(v-else placement="top" content="Set Representing" :disabled="hideTooltips") + el-tooltip(v-else placement="top" :content="$t('dialog.group.actions.represent_tooltip')" :disabled="hideTooltips") span el-button(type="default" icon="el-icon-star-off" circle @click="setGroupRepresentation(groupDialog.id)" style="margin-left:5px" :disabled="groupDialog.ref.privacy === 'private'") template(v-else-if="groupDialog.ref.membershipStatus === 'requested'") - el-tooltip(placement="top" content="Cancel join request" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.group.actions.cancel_join_request_tooltip')" :disabled="hideTooltips") span el-button(type="default" icon="el-icon-close" circle @click="cancelGroupRequest(groupDialog.id)" style="margin-left:5px") template(v-else-if="groupDialog.ref.membershipStatus === 'invited'") - el-tooltip(placement="top" content="Pending invite" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.group.actions.pending_request_tooltip')" :disabled="hideTooltips") span el-button(type="default" icon="el-icon-check" circle @click="joinGroup(groupDialog.id)" style="margin-left:5px") template(v-else) - el-tooltip(v-if="groupDialog.ref.joinState === 'request'" placement="top" content="Request to join" :disabled="hideTooltips") + el-tooltip(v-if="groupDialog.ref.joinState === 'request'" placement="top" :content="$t('dialog.group.actions.request_join_tooltip')" :disabled="hideTooltips") el-button(type="default" icon="el-icon-message" circle @click="joinGroup(groupDialog.id)" style="margin-left:5px") - el-tooltip(v-if="groupDialog.ref.joinState === 'invite'" placement="top" content="Invite required" :disabled="hideTooltips") + el-tooltip(v-if="groupDialog.ref.joinState === 'invite'" placement="top" :content="$t('dialog.group.actions.invite_required_tooltip')" :disabled="hideTooltips") span el-button(type="default" icon="el-icon-message" disabled circle style="margin-left:5px") - el-tooltip(v-if="groupDialog.ref.joinState === 'open'" placement="top" content="Join Group" :disabled="hideTooltips") + el-tooltip(v-if="groupDialog.ref.joinState === 'open'" placement="top" :content="$t('dialog.group.actions.join_group_tooltip')" :disabled="hideTooltips") el-button(type="default" icon="el-icon-check" circle @click="joinGroup(groupDialog.id)" style="margin-left:5px") el-dropdown(trigger="click" @command="groupDialogCommand" size="small" style="margin-left:5px") el-button(type="default" icon="el-icon-more" circle) el-dropdown-menu(#default="dropdown") - el-dropdown-item(icon="el-icon-refresh" command="Refresh") Refresh + el-dropdown-item(icon="el-icon-refresh" command="Refresh") {{ $t('dialog.group.actions.refresh') }} template(v-if="groupDialog.inGroup") template(v-if="groupDialog.ref.myMember") - el-dropdown-item(v-if="groupDialog.ref.myMember.isSubscribedToAnnouncements" icon="el-icon-close" command="Unsubscribe To Announcements" divided) Unsubscribe From Announcements - el-dropdown-item(v-else icon="el-icon-check" command="Subscribe To Announcements" divided) Subscribe To Announcements - el-dropdown-item(v-if="hasGroupPermission(groupDialog.ref, 'group-invites-manage')" icon="el-icon-message" command="Invite To Group") Invite To Group + el-dropdown-item(v-if="groupDialog.ref.myMember.isSubscribedToAnnouncements" icon="el-icon-close" command="Unsubscribe To Announcements" divided) {{ $t('dialog.group.actions.unsubscribe') }} + el-dropdown-item(v-else icon="el-icon-check" command="Subscribe To Announcements" divided) {{ $t('dialog.group.actions.subscribe') }} + el-dropdown-item(v-if="hasGroupPermission(groupDialog.ref, 'group-invites-manage')" icon="el-icon-message" command="Invite To Group") {{ $t('dialog.group.actions.invite_to_group') }} template(v-if="groupDialog.ref.myMember && groupDialog.ref.privacy === 'default'") - el-dropdown-item(icon="el-icon-view" command="Visibility Everyone" divided) #[i.el-icon-check(v-if="groupDialog.ref.myMember.visibility === 'visible'")] Visibility Everyone - el-dropdown-item(icon="el-icon-view" command="Visibility Friends") #[i.el-icon-check(v-if="groupDialog.ref.myMember.visibility === 'friends'")] Visibility Friends - el-dropdown-item(icon="el-icon-view" command="Visibility Hidden") #[i.el-icon-check(v-if="groupDialog.ref.myMember.visibility === 'hidden'")] Visibility Hidden - el-dropdown-item(icon="el-icon-delete" command="Leave Group" style="color:#F56C6C" divided) Leave Group + el-dropdown-item(icon="el-icon-view" command="Visibility Everyone" divided) #[i.el-icon-check(v-if="groupDialog.ref.myMember.visibility === 'visible'")] {{ $t('dialog.group.actions.visibility_everyone') }} + el-dropdown-item(icon="el-icon-view" command="Visibility Friends") #[i.el-icon-check(v-if="groupDialog.ref.myMember.visibility === 'friends'")] {{ $t('dialog.group.actions.visibility_friends') }} + el-dropdown-item(icon="el-icon-view" command="Visibility Hidden") #[i.el-icon-check(v-if="groupDialog.ref.myMember.visibility === 'hidden'")] {{ $t('dialog.group.actions.visibility_hidden') }} + el-dropdown-item(icon="el-icon-delete" command="Leave Group" style="color:#F56C6C" divided) {{ $t('dialog.group.actions.leave') }} el-tabs(ref="groupDialogTabs" @tab-click="groupDialogTabClick") - el-tab-pane(label="Info") + el-tab-pane(:label="$t('dialog.group.info.header')") .group-banner-image-info el-popover(placement="right" width="500px" trigger="click") img.x-link(slot="reference" v-lazy="groupDialog.ref.bannerUrl" style="flex:none;width:100%;aspect-ratio:6/1;object-fit:cover;border-radius:4px") @@ -2261,7 +2261,7 @@ html .x-friend-list(style="max-height:none") .x-friend-item(v-if="groupDialog.ref.membershipStatus === 'member'" style="width:100%;cursor:default") .detail - span.name Announcement + span.name {{ $t('dialog.group.info.announcement') }} span(style="display:block" v-text="groupDialog.announcement.title") div(v-if="groupDialog.announcement.imageUrl" style="display:inline-block;margin-right:5px") el-popover(placement="right" width="500px" trigger="click") @@ -2297,19 +2297,19 @@ html timer(:epoch="user.$location_at") .x-friend-item(style="width:100%;cursor:default") .detail - span.name Rules + span.name {{ $t('dialog.group.info.rules') }} pre.extra(style="font-family:inherit;font-size:12px;white-space:pre-wrap;margin:0 0.5em 0 0") {{ groupDialog.ref.rules || '-' }} .x-friend-item(style="cursor:default") .detail - span.name Members + span.name {{ $t('dialog.group.info.members') }} .extra {{ groupDialog.ref.memberCount }} ({{ groupDialog.ref.onlineMemberCount }}) .x-friend-item(style="cursor:default") .detail - span.name Created + span.name {{ $t('dialog.group.info.created_at') }} span.extra {{ groupDialog.ref.createdAt | formatDate('long') }} .x-friend-item(style="cursor:default") .detail - span.name Links + span.name {{ $t('dialog.group.info.links') }} div(v-if="groupDialog.ref.links && groupDialog.ref.links.length > 0" style="margin-top:5px") el-tooltip(v-if="link" v-for="(link, index) in groupDialog.ref.links" :key="index") template(#content) @@ -2318,45 +2318,45 @@ html .extra(v-else) - .x-friend-item(style="width:350px;cursor:default") .detail - span.name Group URL + span.name {{ $t('dialog.group.info.url') }} span.extra {{ groupDialog.ref.$url }} - el-tooltip(placement="top" content="Copy URL to clipboard" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.group.info.url_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="copyGroupUrl(groupDialog.ref.$url)" size="mini" icon="el-icon-s-order" circle style="margin-left:5px") .x-friend-item(style="width:350px;cursor:default") .detail - span.name Group ID + span.name {{ $t('dialog.group.info.id') }} span.extra {{ groupDialog.id }} - el-tooltip(placement="top" content="Copy ID to clipboard" :disabled="hideTooltips") + el-tooltip(placement="top" :content="$t('dialog.group.info.id_tooltip')" :disabled="hideTooltips") el-button(type="default" @click="copyGroupId(groupDialog.id)" size="mini" icon="el-icon-s-order" circle style="margin-left:5px") div(v-if="groupDialog.ref.membershipStatus === 'member'" style="width:100%;margin-top:10px;border-top:1px solid #e4e7ed14") div(style="width:100%;display:flex;margin-top:10px") .x-friend-item(style="cursor:default") .detail - span.name Joined At + span.name {{ $t('dialog.group.info.joined_at') }} span.extra {{ groupDialog.ref.myMember.joinedAt | formatDate('long') }} .x-friend-item(style="cursor:default") .detail - span.name Roles + span.name {{ $t('dialog.group.info.roles') }} span.extra(v-if="groupDialog.memberRoles.length === 0") - span.extra(v-else) template(v-for="(role, rIndex) in groupDialog.memberRoles" :key="rIndex") el-tooltip(placement="top") template(#content) - span Description: {{ role.description }} + span {{ $t('dialog.group.info.role_description') }} {{ role.description }} br - span(v-if="role.updatedAt") Updated At: {{ role.updatedAt | formatDate('long') }} - span(v-else) Created At: {{ role.createdAt | formatDate('long') }} + span(v-if="role.updatedAt") {{ $t('dialog.group.info.role_updated_at') }} {{ role.updatedAt | formatDate('long') }} + span(v-else) {{ $t('dialog.group.info.role_created_at') }} {{ role.createdAt | formatDate('long') }} br - span Permissions: + span {{ $t('dialog.group.info.role_permissions') }} br template(v-for="(permission, pIndex) in role.permissions" :key="pIndex") span {{ permission }} br span {{ role.name }}{{ rIndex < groupDialog.memberRoles.length - 1 ? ', ' : '' }} - el-tab-pane(label="Members") + el-tab-pane(:label="$t('dialog.group.members.header')") template(v-if="groupDialog.visible && groupDialog.ref.membershipStatus === 'member'") - span(v-if="hasGroupPermission(groupDialog.ref, 'group-members-viewall')" style="font-weight:bold;font-size:16px") All Members - span(v-else style="font-weight:bold;font-size:16px") Friends Only + span(v-if="hasGroupPermission(groupDialog.ref, 'group-members-viewall')" style="font-weight:bold;font-size:16px") {{ $t('dialog.group.members.all_members') }} + span(v-else style="font-weight:bold;font-size:16px") {{ $t('dialog.group.members.friends_only') }} br el-button(type="default" @click="getGroupDialogGroupMembers()" size="mini" icon="el-icon-refresh" circle) span(style="font-size:14px;margin-left:5px;margin-right:5px") {{ groupDialog.members.length }}/{{ groupDialog.ref.memberCount }} @@ -2369,8 +2369,8 @@ html span.extra .x-friend-item(v-if="!isGroupMembersDone" v-loading="isGroupMembersLoading" style="width:100%;height:45px;text-align:center" @click="loadMoreGroupMembers") .detail(v-if="!isGroupMembersLoading") - span.name Load more... - el-tab-pane(label="JSON") + span.name {{ $t('dialog.group.members.load_more') }} + el-tab-pane(:label="$t('dialog.group.json.header')") el-button(type="default" @click="refreshGroupDialogTreeData()" size="mini" icon="el-icon-refresh" circle) el-tree(:data="groupDialog.treeData" style="margin-top:5px;font-size:12px") template(#default="scope") @@ -2432,57 +2432,57 @@ html el-button(type="primary" size="small" :disabled="inviteDialog.loading || !inviteDialog.userIds.length" @click="sendInvite()") Invite //- dialog: social status - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="socialStatusDialog" :visible.sync="socialStatusDialog.visible" title="Social Status" width="400px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="socialStatusDialog" :visible.sync="socialStatusDialog.visible" :title="$t('dialog.social_status.header')" width="400px") div(v-loading="socialStatusDialog.loading") el-collapse(style="border:0") el-collapse-item template(slot="title") - span(style="font-size:16px") History + span(style="font-size:16px") {{ $t('dialog.social_status.history') }} data-tables(v-bind="socialStatusHistoryTable" @row-click="setSocialStatusFromHistory" style="cursor:pointer") - el-table-column(label="No" prop="no" width="40") - el-table-column(label="Status" prop="status") + el-table-column(:label="$t('table.social_status.no')" prop="no" width="40") + el-table-column(:label="$t('table.social_status.status')" prop="status") el-select(v-model="socialStatusDialog.status" style="dispaly:block;margin-top:10px") - el-option(label="Online" value="active"). - #[i.x-user-status.online] Online - el-option(label="Join Me" value="join me"). - #[i.x-user-status.joinme] Join Me - el-option(label="Ask Me" value="ask me"). - #[i.x-user-status.askme] Ask Me - el-option(label="Do Not Disturb" value="busy"). - #[i.x-user-status.busy] Do Not Disturb - el-option(v-if="API.currentUser.$isModerator" label="Offline" value="offline"). - #[i.x-user-status.offline] Offline - el-input(v-model="socialStatusDialog.statusDescription" placeholder="Status" maxlength="32" show-word-limit style="dispaly:block;margin-top:10px") + el-option(:label="$t('dialog.user.status.online')" value="active"). + #[i.x-user-status.online] {{ $t('dialog.user.status.online') }} + el-option(:label="$t('dialog.user.status.join_me')" value="join me"). + #[i.x-user-status.joinme] {{ $t('dialog.user.status.join_me') }} + el-option(:label="$t('dialog.user.status.ask_me')" value="ask me"). + #[i.x-user-status.askme] {{ $t('dialog.user.status.ask_me') }} + el-option(:label="$t('dialog.user.status.busy')" value="busy"). + #[i.x-user-status.busy] {{ $t('dialog.user.status.busy') }} + el-option(v-if="API.currentUser.$isModerator" :label="$t('dialog.user.status.offline')" value="offline"). + #[i.x-user-status.offline] {{ $t('dialog.user.status.offline') }} + el-input(v-model="socialStatusDialog.statusDescription" :placeholder="$t('dialog.social_status.status_placeholder')" maxlength="32" show-word-limit style="dispaly:block;margin-top:10px") template(#footer) - el-button(type="primary" size="small" :disabled="socialStatusDialog.loading" @click="saveSocialStatus") Update + el-button(type="primary" size="small" :disabled="socialStatusDialog.loading" @click="saveSocialStatus") {{ $t('dialog.social_status.update') }} //- dialog: language - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="languageDialog" :visible.sync="languageDialog.visible" title="Language" width="400px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="languageDialog" :visible.sync="languageDialog.visible" :title="$t('dialog.language.header')" width="400px") div(v-loading="languageDialog.loading") div(style="margin:5px 0") el-tag(v-for="item in API.currentUser.$languages" :key="item.key" size="small" type="info" effect="plain" closable @close="removeUserLanguage(item.key)" style="margin-right:5px") span.flags(:class="languageClass(item.key)" style="display:inline-block;margin-right:5px") | {{ item.value }} ({{ item.key }}) div(v-if="languageDialog.languageChoice === true") - el-select(v-model="languageDialog.languageValue" size="mini") + el-select(v-model="languageDialog.languageValue" :placeholder="$t('dialog.language.select_language')" size="mini") el-option(v-for="item in languageDialog.languages" :key="item.key" :value="item.key" :label="item.value") span.flags(:class="languageClass(item.key)" style="display:inline-block;margin-right:5px") | {{ item.value }} ({{ item.key }}) - el-button(@click="languageDialog.languageChoice=false; addUserLanguage(languageDialog.languageValue)" size="mini") Ok - el-button(@click="languageDialog.languageChoice=false" size="mini" style="margin-left:0") Cancel + el-button(@click="languageDialog.languageChoice=false; addUserLanguage(languageDialog.languageValue)" size="mini") {{ $t('dialog.language.ok') }} + el-button(@click="languageDialog.languageChoice=false" size="mini" style="margin-left:0") {{ $t('dialog.language.cancel') }} div(v-else) - el-button(@click="languageDialog.languageValue='';languageDialog.languageChoice=true" size="mini") Add Language + el-button(@click="languageDialog.languageValue='';languageDialog.languageChoice=true" size="mini") {{ $t('dialog.language.add_language') }} //- dialog: bio - el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="bioDialog" :visible.sync="bioDialog.visible" title="Bio" width="600px") + el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="bioDialog" :visible.sync="bioDialog.visible" :title="$t('dialog.bio.header')" width="600px") div(v-loading="bioDialog.loading") - el-input(type="textarea" v-model="bioDialog.bio" size="mini" maxlength="512" show-word-limit :autosize="{ minRows:2, maxRows:5 }" placeholder="Please input a bio") + el-input(type="textarea" v-model="bioDialog.bio" size="mini" maxlength="512" show-word-limit :autosize="{ minRows:2, maxRows:5 }" :placeholder="$t('dialog.bio.bio_placeholder')") el-input(v-for="(link, index) in bioDialog.bioLinks" :key="index" :value="link" v-model="bioDialog.bioLinks[index]" size="small" style="margin-top:5px") img(slot="prepend" :src="getFaviconUrl(link)" style="width:16px;height:16px") el-button(slot="append" icon="el-icon-delete" @click="bioDialog.bioLinks.splice(index, 1)") - el-button(@click="bioDialog.bioLinks.push('')" size="mini" style="margin-top:5px") Add Link + el-button(@click="bioDialog.bioLinks.push('')" size="mini" style="margin-top:5px") {{ $t('dialog.bio.add_link') }} template(#footer) - el-button(type="primary" size="small" :disabled="bioDialog.loading" @click="saveBio") Update + el-button(type="primary" size="small" :disabled="bioDialog.loading" @click="saveBio") {{ $t('dialog.bio.update') }} //- dialog: new instance el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="newInstanceDialog" :visible.sync="newInstanceDialog.visible" title="New Instance" width="600px") @@ -2580,7 +2580,7 @@ html | These options are for advanced users only. #[br] | Leave field empty to set as default, game restart required to apply settings. br - span Cache Size: + span Cache Size: span(v-text="VRChatUsedCacheSize") span / span(v-text="VRChatTotalCacheSize") @@ -3347,7 +3347,7 @@ html div(style="float:right;margin-top:5px") el-button(type="default" @click="downloadAndSaveImage(image.versions[image.versions.length - 1].file.url)" size="mini" icon="el-icon-paperclip" circle) el-button(type="default" @click="deleteVRCPlusIcon(image.id)" size="mini" icon="el-icon-delete" circle style="margin-left:5px") - + //- dialog Table: Previous Instances User el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="previousInstancesUserDialog" :visible.sync="previousInstancesUserDialog.visible" title="Previous Instances" width="800px") span(v-text="previousInstancesUserDialog.userRef.displayName" style="font-size:14px") @@ -3373,7 +3373,7 @@ html el-button(type="text" icon="el-icon-info" size="mini" @click="showLaunchDialog(scope.row.location)") el-button(type="text" icon="el-icon-tickets" size="mini" @click="showPreviousInstanceInfoDialog(scope.row.location)") el-button(type="text" icon="el-icon-close" size="mini" @click="confirmDeleteGameLogUserInstance(scope.row)") - + //- dialog Table: Previous Instances World el-dialog.x-dialog(:before-close="beforeDialogClose" @mousedown.native="dialogMouseDown" @mouseup.native="dialogMouseUp" ref="previousInstancesWorldDialog" :visible.sync="previousInstancesWorldDialog.visible" title="Previous Instances" width="800px") span(v-text="previousInstancesWorldDialog.worldRef.name" style="font-size:14px") diff --git a/html/src/localization/localizedStrings.js b/html/src/localization/localizedStrings.js new file mode 100644 index 00000000..d33c20c8 --- /dev/null +++ b/html/src/localization/localizedStrings.js @@ -0,0 +1,5 @@ +import en from './strings/en.json' assert { type: 'JSON' }; +// import ja from './strings/ja.json' assert { type: 'JSON' }; +import zh_TW from './strings/zh_TW.json' assert { type: 'JSON' }; + +export { en, zh_TW }; \ No newline at end of file diff --git a/html/src/localization/strings/en.json b/html/src/localization/strings/en.json new file mode 100644 index 00000000..695ffa59 --- /dev/null +++ b/html/src/localization/strings/en.json @@ -0,0 +1,800 @@ +{ + "language": "English", + "translator": "-", + "nav_tooltip": { + "feed": "Feed", + "game_log": "Game Log", + "player_list": "Player List", + "search": "Search", + "favorites": "Favorites", + "friend_log": "Friend Log", + "moderation": "Moderation", + "notification": "Notification", + "friend_list": "Friend List", + "profile": "Profile", + "settings": "Settings" + }, + "view": { + "login": { + "savedAccounts": "Saved Accounts", + "login": "Login", + "register": "Register", + "forgotPassword": "Forgot Password?", + "field": { + "username": "Username or Email", + "password": "Password", + "saveCredentials": "Save Credentials", + "devEndpoint": "Dev Endpoint", + "endpoint": "Endpoint", + "websocket": "WebSocket" + } + }, + "feed": { + "favorites_only_tooltip": "Filter VIP only", + "filter_placeholder": "Filter", + "search_placeholder": "Search" + }, + "game_log": { + "filter_placeholder": "Filter", + "search_placeholder": "Search" + }, + "search": { + "search_placeholder": "Search", + "clear_results_tooltip": "Clear Search Results", + "user": { + "header": "User" + }, + "world": { + "header": "World", + "category": "Search by category", + "community_lab": "Include community labs" + }, + "avatar": { + "header": "Avatar", + "search_provider": "Search Provider", + "refresh_tooltip": "Refresh own avatars", + "result_count": "Results {count}", + "all": "All", + "public": "Public", + "private": "Private", + "local": "Local", + "remote": "Remote", + "sort_name": "Sort by name", + "sort_update": "Sort by update", + "sort_created": "Sort by created" + }, + "prev_page": "Prev", + "next_page": "Nect" + }, + "favorite": { + "friends": { + "header": "Friends" + }, + "worlds": { + "header": "Worlds", + "vrchat_favorites": "VRChat Favorites", + "local_favorites": "Local Favorites", + "new_group": "New Group" + }, + "avatars": { + "header": "Avatars" + }, + "refresh_tooltip": "Refresh all favorites", + "export": "Export", + "import": "Import", + "move_tooltip": "Move", + "unfavorite_tooltip": "Unfavorite", + "visibility_tooltip": "Change Visibility", + "rename_tooltip": "Rename", + "clear_tooltip": "Clear", + "delete_tooltip": "Delete" + }, + "friend_log": { + "filter_placeholder": "Filter", + "search_placeholder": "Search" + }, + "moderation": { + "filter_placeholder": "Filter", + "search_placeholder": "Search", + "refresh_tooltip": "Refresh" + }, + "notification": { + "filter_placeholder": "Filter", + "search_placeholder": "Search", + "refresh_tooltip": "Refresh" + }, + "friend_list": { + "header": "Friend List", + "bulk_unfriend": "Bulk Unfriend Mode", + "bulk_unfriend_selection": "Bulk Unfriend Selection", + "load": "Load missing entries", + "load_notice": "This takes a lot of API requests so use it sparingly", + "load_tooltip": "Load", + "favorites_only_tooltip": "Filter VIP only", + "search_placeholder": "Search", + "filter_placeholder": "Filter", + "refresh_tooltip": "Refresh", + "clear_tooltip": "Clear Results" + }, + "profile": { + "profile": { + "header": "Profile", + "last_activity": "Last Activity", + "two_factor": "Two-Factor Auth (2FA)", + "two_factor_enabled": "Enabled", + "two_factor_disabled": "Disabled", + "logout": "Logout", + "export_friend_list": "Export Friends List", + "export_own_avatars": "Export Own Avatars", + "discord_names": "Discord Names", + "export_notes": "Export Notes" + }, + "game_info": { + "header": "Game Info", + "online_users": "Online Users", + "user_online": "{count} users online.", + "refresh": "Click to refresh" + }, + "vrc_sdk_downloads": { + "header": "VRC SDK Downloads" + }, + "direct_access": { + "header": "Direct Access", + "username": "Username", + "user_id": "User ID", + "world_instance": "World/Instance", + "avatar": "Avatar" + }, + "invite_messages": "Invite Messages", + "invite_response_messages": "Invite Response Messages", + "invite_request_messages": "Invite Request Messages", + "invite__request_response_messages": "Invite Request Response Messages", + "past_display_names": "Past Display Names", + "config_json": "Config JSON", + "current_user_json": "Current User JSON", + "refresh_tooltip": "Refresh", + "clear_results_tooltip": "Clear results" + }, + "settings": { + "header": "Settings", + "category": { + "general": "General", + "appearance": "Appearance", + "notifications": "Notifications", + "wrist_overlay": "Wrist Overlay", + "discord_presence": "Discord Presence", + "advanced": "Advanced" + }, + "general": { + "general": { + "header": "General", + "version": "Version", + "latest_app_version": "Latest Version", + "latest_app_version_refresh": "Click to refresh", + "repository_url": "Repository URL", + "support": "Support" + }, + "vrcx_updater": { + "header": "VRCX Updater", + "change_build": "Change build", + "auto_update": "Auto update", + "auto_update_off": "Off", + "auto_update_notify": "Notify", + "auto_update_download": "Auto Download", + "auto_update_install": "Auto Install" + }, + "application": { + "header": "Application", + "startup": "Start as Windows startup", + "minimized": "Start as minimized state", + "tray": "Close to tray" + }, + "legal_notice": { + "header": "Legal Notice", + "info": "VRCX is an assistant application for provide information about manage friendship. this application uses unofficial VRChat API (VRCSDK).", + "disclaimer1": "VRCX isn't endorsed by VRChat and doesn't reflect the views or opinions of VRChat or anyone officially involved in producing or managing VRChat. VRChat is trademark of VRChat Inc. VRChat © VRChat Inc.", + "disclaimer2": "pypy or Natsumi aren't responsible for any problems caused by VRCX. Use at your own risk!", + "open_source_software_notice": "Open Source Software Notice" + } + }, + "appearance": { + "appearance": { + "header": "Appearance", + "theme_mode": "Theme mode", + "theme_mode_system": "System", + "theme_mode_light": "Light", + "theme_mode_dark": "Dark", + "vrcplus_profile_icons": "VRCPlus Profile Icons", + "disable_tooltips": "Disable Tooltips", + "sort_favorite_by": "Sort Favorites by", + "sort_favorite_by_name": "name", + "sort_favorite_by_date": "date", + "sort_instance_users_by": "Sort Instance Users by", + "sort_instance_users_by_time": "time", + "sort_instance_users_by_alphabet": "alphabetical", + "table_max_size": "Table Max Size", + "page_size": "Page Size:" + }, + "timedate": { + "header": "Time/Date", + "time_format": "Time Format", + "time_format_24": "24 Hour", + "time_format_12": "12 Hour", + "force_iso_date_format": "Force ISO Date Format" + }, + "side_panel": { + "header": "Side Panel", + "sorting": { + "header": "Sorting", + "sort_private_to_bottom": "Sort Private to bottom", + "sort_by_status": "Sort by status", + "sort_gps_to_top": "Sort GPS to top", + "sort_gps_to_top_notice": "(online for only)", + "sort_favorite_by": "Sort VIP by", + "sort_favorite_by_alphabet": "alphabetical", + "sort_favorite_by_online_time": "online for", + "sort_online_by": "Sort Online by", + "sort_online_by_alphabet": "alphabetical", + "sort_online_by_online_time": "online for", + "sort_active_by": "Sort Active by", + "sort_active_by_alphabet": "alphabetical", + "sort_active_by_online_time": "online for", + "sort_offline_by": "Sort Offline by", + "sort_offline_by_alphabet": "alphabetical", + "sort_offline_by_offline_time": "offline for" + }, + "width": "Width" + }, + "user_dialog": { + "header": "User Dialog", + "hide_vrchat_notes": "Hide VRChat Notes", + "hide_vrcx_memos": "Hide VRCX Memos", + "export_vrcx_memos_into_vrchat_notes": "Export VRCX Memos into VRChat notes", + "export_notes": "Export Notes" + }, + "user_colors": { + "header": "User Colors", + "random_colors_from_user_id": "Random Colors from User ID" + } + }, + "notifications": { + "notifications": { + "header": "Notifications", + "notification_filter": "Notification Filter", + "steamvr_notifications": { + "header": "SteamVR Notifications", + "steamvr_overlay": "SteamVR Overlay", + "overlay_notifications": "Overlay Notifications", + "notification_position": "Notification Position", + "xsoverlay_notifications": "XSOverlay Notifications", + "user_images": "User Images (slower)", + "notification_timeout": "Notification Timeout" + }, + "desktop_notifications": { + "header": "Desktop Notifications", + "when_to_display": "When to display", + "when_to_display_never": "Never", + "when_to_display_desktop": "Desktop Mode", + "when_to_display_inside_vr": "Inside VR", + "when_to_display_outside_vr": "Outside VR", + "when_to_display_game_closed": "Game Closed", + "when_to_display_game_running": "Game Running", + "when_to_display_always": "Always" + }, + "text_to_speech": { + "header": "Text-To-Speech Options", + "when_to_play": "Notification TTS. When to play", + "when_to_play_never": "Never", + "when_to_play_inside_vr": "Inside VR", + "when_to_play_game_closed": "Game Closed", + "when_to_play_game_running": "Game Running", + "when_to_play_always": "Always", + "tts_voice": "TTS Voice" + } + } + }, + "wrist_overlay": { + "steamvr_wrist_overlay": { + "header": "SteamVR Wrist Overlay", + "description": "* It runs automatically when VRChat is running.", + "grip": "Grip: Vive or Other Controllers Grab, Oculus X/A Buttons", + "menu": "Menu: Vive Menu, Index B, Oculus Y/B Buttons", + "steamvr_overlay": "SteamVR Overlay", + "wrist_feed_overlay": "Wrist Feed Overlay", + "hide_private_worlds": "Hide Private Worlds", + "start_overlay_with": "Start Overlay With", + "overlay_button": "Overlay Button", + "overlay_button_grip": "Grip", + "overlay_button_menu": "Menu", + "display_overlay_on": "Display Overlay On", + "display_overlay_on_left": "Left Hand", + "display_overlay_on_right": "Right Hand", + "display_overlay_on_both": "Both Hand", + "background_color": "Background Color", + "minimal_feed_icons": "Minimal Feed Icons", + "hide_vr_devices": "Hide VR Devices", + "hide_cpu_usage": "Hide CPU Usage", + "hide_game_uptime": "Hide Game Uptime", + "show_pc_uptime": "Show PC Uptime", + "wrist_feed_filters": "Wrist Feed Filters" + } + }, + "discord_presence": { + "discord_presence": { + "header": "Discord Presence", + "description": "* Only works when VRChat is running.", + "enable": "Enable", + "enable_tooltip": "Recommended to disable Rich Presence in VRChat config.json to stop it from conflicting", + "instance_type_player_count": "Instance type/player count", + "join_button": "Join button (public only)", + "hide_details_in_private": "Hide world details in private", + "hide_images": "Hide World Images" + } + }, + "advanced": { + "advanced": { + "header": "Advanced", + "launch_options": "Launch Options", + "pending_offline": { + "header": "Pending Offline", + "description": "Delay before marking user as offline (fixes false positives)", + "set_delay": "Set Delay" + }, + "primary_password": { + "header": "Primary Password", + "description": "Encrypt password (disables auto login)" + }, + "vrchat_quit_fix": { + "header": "VRChat Quit Fix", + "description": "Kill VRChat after exiting game" + }, + "auto_cache_management": { + "header": "Automatically Manage Cache When Closing VRChat", + "description": "Auto delete old versions from cache" + }, + "remote_database": { + "header": "Remote Avatar Database", + "enable": "Enable", + "avatar_database_provider": "Avatar Database Provider" + }, + "youtube_api": { + "header": "Youtube API", + "enable": "Enable", + "youtube_api_key": "Youtube API Key" + }, + "video_progress_pie": { + "header": "Progress pie overlay for videos", + "enable": "Enable", + "enable_tooltip": "Requires SteamVR overlay to be enabled", + "dance_world_only": "Dance worlds only" + }, + "cache_debug": { + "header": "VRCX Instance Cache/Debug", + "disable_gamelog": "Disable GameLog", + "disable_gamelog_notice": "(will likely break things)", + "user_cache": "User cache:", + "world_cache": "World cache:", + "avatar_cache": "Avatar cache:", + "avatar_name_cache": "Avatar Name cache:", + "clear_cache": "Clear Cache", + "auto_clear_cache": "Auto Clear Cache", + "download_history": "Download History", + "show_console": "Show Console" + }, + "sqlite_table_size": { + "header": "SQLite Table Size", + "refresh": "Refresh", + "gps": "GPS:", + "status": "Status:", + "bio": "Bio:", + "avatar": "Avatar:", + "online_offline": "Online/Offline:", + "friend_log_history": "Friend Log History:", + "notification": "Notifications:", + "location": "Location:", + "join_leave": "Join/Leave:", + "portal_spawn": "Portal Spawn:", + "video_play": "Video Play:", + "event": "Event:" + } + }, + "photon": { + "header": "Photon Logging Overlay", + "event_hud": { + "header": "Photon Event HUD", + "enable": "Enable", + "enable_tooltip": "Requires SteamVR overlay to be enabled", + "filter": "Filter", + "filter_favorites": "VIP", + "filter_friends": "Friends", + "filter_everyone": "Everyone", + "message_timeout": "Message Timeout" + }, + "timeout_hud": { + "header": "User Timeout HUD", + "enable": "Enable", + "enable_tooltip": "Requires SteamVR overlay to be enabled", + "filter": "Filter", + "filter_favorites": "VIP", + "filter_friends": "Friends", + "filter_everyone": "Everyone", + "timeout_threshold": "Timeout Threshold" + } + } + } + } + }, + "side_panel": { + "search_placeholder": "Search", + "search_result_active": "Offline", + "search_result_offline": "Active", + "search_result_more": "Search More:", + "direct_access_tooltip": "Direct access ID/URL from clipboard", + "refresh_tooltip": "Refresh friends", + "friends": "FRIENDS", + "me": "ME", + "favorite": "VIP", + "online": "ONLINE", + "active": "ACTIVE", + "offline": "OFFLINE", + "penfing_offline": "Pending Offline" + }, + "dialog": { + "user": { + "status": { + "active": "Active", + "offline": "Offline", + "online": "Online", + "join_me": "Join Me", + "ask_me": "Ask Me", + "busy": "Do Not Disturb" + }, + "previous_display_names": "Previous Display Names:", + "tags": { + "friend_no": "Friend No.{number}", + "vrchat_team": "VRChat Team" + }, + "actions": { + "favorite_tooltip": "Add to favorites", + "unfavorite_tooltip": "Remove from favorites", + "refresh": "Refresh", + "copy_url": "Copy User URL", + "invite": "Invite", + "invite_with_message": "Invite With Message", + "request_invite": "Request Invite", + "request_invite_with_message": "Request Invite With Message", + "invite_to_group": "Invite To Group", + "manage_gallery_icon": "Manage Gallery/Icons", + "accept_friend_request": "Accept Friend Request", + "decline_friend_request": "Decline Friend Request", + "cancel_friend_request": "Cancel Friend Request", + "send_friend_request": "Send Friend Request", + "show_avatar_author": "Show Avatar Author", + "show_fallback_avatar": "Show Fallback Avatar Details", + "show_previous_instances": "Show Previous Instances", + "show_previous_images": "Show Previous Images", + "moderation_block": "Block", + "moderation_unblock": "Unblock", + "moderation_mute": "Mute", + "moderation_unmute": "Unmute", + "moderation_hide_avatar": "Show Avatar", + "moderation_show_avatar": "Hide Avatar", + "moderation_enable_avatar_interaction": "Enable Avatar Interaction", + "moderation_disable_avatar_interaction": "Disable Avatar Interaction", + "edit_status": "Social Status", + "edit_language": "Language", + "edit_bio": "Bio", + "unfriend": "Unfriend", + "logout": "Logout" + }, + "info": { + "header": "Info", + "launch_invite_tooltip": "Launch/Invite", + "self_invite_tooltip": "Invite Yourself", + "refresh_user_count_tooltip": "Refresh User Count", + "instance_creator": "Instance Creator", + "note": "Note", + "note_placeholder": "Click to add a note", + "memo": "Memo", + "memo_placeholder": "Click to add a memo", + "avatar_info": "Avatar Info", + "avatar_info_last_seen": "Avatar Info Last Seen", + "represented_group": "Represented Group", + "bio": "Bio", + "last_seen": "Last Seen", + "join_count": "Join Count", + "time_together": "Time Together", + "online_for": "Online For", + "offline_for": "Offline For", + "last_activity": "Last Activity", + "last_login": "Last Login", + "date_joined": "Date Joined", + "friended": "Friended", + "unfriended": "Unfriended", + "avatar_cloning": "Avatar Cloning", + "avatar_cloning_allow": "Allowed", + "avatar_cloning_deny": "Deny", + "home_location": "Home Location", + "accuracy_notice": "Info from local database may not be accurate" + }, + "groups": { + "header": "Groups", + "total_count": "Total {count}", + "own_groups": "Own Groups", + "mutual_groups": "Mutual Groups", + "groups": "Groups" + }, + "worlds": { + "header": "Worlds", + "total_count": "Total {count}", + "sort_by_name": "Sort by name", + "sort_by_update": "Sort by update" + }, + "favorite_worlds": { + "header": "Favorite Worlds" + }, + "avatars": { + "header": "Avatars", + "total_count": "Total {count}", + "sort_by_name": "Sort by name", + "sort_by_update": "Sort by update", + "all": "All", + "public": "Public", + "private": "Private" + }, + "json": { + "header": "JSON" + } + }, + "world": { + "tags": { + "public": "Public", + "private": "Private", + "labs": "Labs", + "cache": "Cache" + }, + "actions": { + "delete_cache_tooltip": "Delete world from cache", + "favorite_tooltip": "Add to favorites", + "unfavorite_tooltip": "Remove from favorites", + "refresh": "Refresh", + "new_instance": "New Instance", + "make_home": "Make Home", + "reset_home": "Reset Home", + "show_previous_instances": "Show Previous Instances", + "show_previous_images": "Show Previous Images", + "rename": "Rename", + "change_description": "Change Description", + "change_capacity": "Change Capacity", + "change_preview": "Change Youtube Preview", + "change_tags": "Change Tags", + "change_image": "Change Image", + "download_package": "Download Unity Package", + "publish_to_labs": "Publish To Labs", + "unpublish": "Unpublish", + "delete": "Delete" + }, + "instances": { + "header": "Instances", + "public_count": "Public {count}", + "private_count": "Private {count}", + "capacity_count": "Capacity {count} ({max})", + "self_invite_tooltip": "Invite Yourself", + "refresh_user_count_tooltip": "Refresh User Count", + "instance_creator": "Instance Creator" + }, + "info": { + "header": "Info", + "id": "World ID", + "id_tooltip": "Copy to clipboard", + "copy_id": "Copy ID", + "copy_url": "Copy URL", + "youtube_preview": "Youtube Preview", + "players": "Players", + "favorites": "Favorites", + "visits": "Visits", + "capacity": "Capacity", + "heat": "Heat", + "popularity": "Popularity", + "created_at": "Created At", + "last_updated": "Last Updated", + "version": "Version", + "platform": "Platform", + "last_visited": "Last Visited", + "visit_count": "Visit Count", + "time_spent": "Time Spent", + "accuracy_notice": "Info from local database may not be accurate" + }, + "json": { + "header": "JSON" + } + }, + "avatar": { + "tags": { + "public": "Public", + "private": "Private", + "fallback": "Fallback", + "cache": "Cache" + }, + "actions": { + "delete_cache_tooltip": "Delete avatar from cache", + "favorite_tooltip": "Add to favorites", + "unfavorite_tooltip": "Remove from favorites", + "refresh": "Refresh", + "select": "Select Avatar", + "select_fallback": "Select Fallback Avatar", + "block": "Block Avatar", + "unblock": "Unblock Avatar", + "show_previous_images": "Show Previous Images", + "make_public": "Make Public", + "make_private": "Make Private", + "rename": "Rename", + "change_description": "Change Description", + "change_image": "Change Image", + "download_package": "Download Unity Package", + "delete": "Delete" + }, + "info": { + "header": "Info", + "id": "Avatar ID", + "id_tooltip": "Copy to clipboard", + "copy_id": "Copy ID", + "copy_url": "Copy URL", + "created_at": "Created At", + "last_updated": "Last Updated", + "version": "Version", + "platform": "Platform" + }, + "json": { + "header": "JSON" + } + }, + "group": { + "tags": { + "verified": "Verified", + "public": "Public", + "private": "Private", + "open": "Open", + "request": "Request", + "invite": "Invite", + "closed": "Closed", + "joined": "Joined", + "banned": "Banned", + "visible": "Visible", + "friends": "Friends", + "hidden": "Hidden", + "subscribed": "Subscribed" + }, + "actions": { + "represent_tooltip": "Set Representing", + "unrepresent_tooltip": "Stop Representing", + "cancel_join_request_tooltip": "Cancel join request", + "pending_request_tooltip": "Pending invite", + "request_join_tooltip": "Request to join", + "invite_required_tooltip": "Invite required", + "join_group_tooltip": "Join Group", + "refresh": "Refresh", + "unsubscribe": "Unsubscribe From Announcements", + "subscribe": "Subscribe To Announcements", + "invite_to_group": "Invite To Group", + "visibility_everyone": "Visibility Everyone", + "visibility_friends": "Visibility Friends", + "visibility_hidden": "Visibility Hidden", + "leave": "Leave Group" + }, + "info": { + "header": "Info", + "announcement": "Announcement", + "rules": "Rules", + "members": "Members", + "created_at": "Created At", + "links": "Links", + "url": "Group URL", + "url_tooltip": "Copy URL to clipboard", + "id": "Group ID", + "id_tooltip": "Copy ID to clipboard", + "joined_at": "Joined At", + "roles": "Roles", + "role_description": "Description:", + "role_updated_at": "Updated At:", + "role_created_at": "Created At:", + "role_permissions": "Permissions:" + }, + "members": { + "header": "Members", + "all_members": "All Members", + "friends_only": "Friends Only", + "load_more": "Load more..." + }, + "json": { + "header": "JSON" + } + }, + "social_status": { + "header": "Social Status", + "history": "History", + "status_placeholder": "Status", + "update": "Update" + }, + "language": { + "header": "Language", + "add_language": "Add Language", + "select_language": "Select Language", + "ok": "OK", + "cancel": "Cancel" + }, + "bio": { + "header": "Bio", + "bio_placeholder": "Please input a bio", + "add_link": "Add Link", + "update": "Update" + } + }, + "table": { + "feed": { + "date": "Date", + "type": "Type", + "user": "User", + "detail": "Detail" + }, + "gameLog": { + "date": "Date", + "type": "Type", + "user": "User", + "detail": "Detail" + }, + "playerList": { + "avatar": "Avatar", + "timer": "Timer", + "photonId": "Photon ID", + "icon": "Icons", + "platform": "Platform", + "displayName": "Display Name", + "status": "Status", + "rank": "Rank", + "language": "Language", + "bioLink": "Bio Links" + }, + "friendLog": { + "date": "Date", + "type": "Type", + "user": "User", + "action": "Action" + }, + "moderation": { + "date": "Date", + "type": "Type", + "source": "Source", + "target": "Target", + "action": "Action" + }, + "notification": { + "date": "Date", + "type": "Type", + "user": "User", + "photo": "Photo", + "message": "Message", + "action": "Action" + }, + "friendList": { + "no": "No.", + "avatar": "Avatar", + "displayName": "Display Name", + "rank": "Rank", + "status": "Status", + "language": "Language", + "bioLink": "Bio Links", + "joinCount": "Join Counts", + "timeTogether": "Time Together", + "lastSeen": "Last Seen", + "lastActivity": "Last Activity", + "lastLogin": "Last Login", + "dateJoined": "Date Joined", + "unfriend": "Unfriend" + }, + "social_status": { + "no": "No.", + "status": "Status" + } + } +} \ No newline at end of file diff --git a/html/src/localization/strings/zh_TW.json b/html/src/localization/strings/zh_TW.json new file mode 100644 index 00000000..3cc0bd9e --- /dev/null +++ b/html/src/localization/strings/zh_TW.json @@ -0,0 +1,802 @@ +{ + "language": "繁體中文", + "translator": "Kamiya", + "nav_tooltip": { + "feed": "動態", + "game_log": "遊戲紀錄", + "player_list": "玩家列表", + "search": "搜尋", + "favorites": "最愛", + "friend_log": "好友紀錄", + "moderation": "玩家處置", + "notification": "通知", + "friend_list": "好友列表", + "profile": "個人檔案", + "settings": "設定" + }, + "view": { + "login": { + "savedAccounts": "已儲存的帳號", + "login": "登入", + "register": "註冊", + "forgotPassword": "忘記密碼?", + "field": { + "username": "玩家名稱或電子郵件", + "password": "密碼", + "saveCredentials": "儲存登入資料", + "devEndpoint": "開發接口", + "endpoint": "Endpoint", + "websocket": "WebSocket" + } + }, + "feed": { + "favorites_only_tooltip": "僅篩選最愛", + "filter_placeholder": "篩選動態", + "search_placeholder": "搜尋動態" + }, + "game_log": { + "filter_placeholder": "篩選遊戲紀錄", + "search_placeholder": "搜尋遊戲紀錄" + }, + "search": { + "search_placeholder": "搜尋", + "clear_results_tooltip": "清除搜尋結果", + "user": { + "header": "玩家" + }, + "world": { + "header": "世界", + "category": "依類別搜尋", + "community_lab": "包含社區實驗室" + }, + "avatar": { + "header": "角色", + "search_provider": "搜尋提供芳", + "refresh_tooltip": "重新整理自己的角色", + "result_count": "{count} 個搜尋結果", + "all": "所有", + "public": "公開", + "private": "私人", + "local": "本地", + "remote": "遠端", + "sort_name": "依名稱排序", + "sort_update": "依更新排序", + "sort_created": "依建立時間排序" + }, + "prev_page": "上一頁", + "next_page": "下一頁" + }, + "favorite": { + "friends": { + "header": "好友" + }, + "worlds": { + "header": "世界", + "vrchat_favorites": "VRChat 最愛", + "local_favorites": "本地最愛", + "new_group": "新群組" + }, + "avatars": { + "header": "角色" + }, + "refresh_tooltip": "重新整理所有最愛", + "export": "匯出", + "import": "匯入", + "move_tooltip": "移動", + "unfavorite_tooltip": "解除最愛", + "visibility_tooltip": "變更可見度", + "rename_tooltip": "重新命名", + "clear_tooltip": "清除", + "delete_tooltip": "刪除" + }, + "friend_log": { + "filter_placeholder": "篩選好友紀錄", + "search_placeholder": "搜尋好友紀錄" + }, + "moderation": { + "filter_placeholder": "篩選玩家處置", + "search_placeholder": "搜尋玩家處置", + "refresh_tooltip": "重新整理" + }, + "notification": { + "filter_placeholder": "篩選通知", + "search_placeholder": "搜尋通知", + "refresh_tooltip": "重新整理" + }, + "friend_list": { + "header": "好友列表", + "bulk_unfriend": "批量解除好友", + "bulk_unfriend_selection": "批量解除已選擇的好友", + "load": "讀取缺失的項目", + "load_notice": "這會向 API 傳送大量請求,所以請謹慎使用", + "load_tooltip": "讀取", + "cancel_tooltip": "取消", + "favorites_only_tooltip": "僅篩選最愛", + "search_placeholder": "搜尋好友", + "filter_placeholder": "篩選好友", + "refresh_tooltip": "重新整理", + "clear_tooltip": "清除結果" + }, + "profile": { + "profile": { + "header": "個人檔案", + "last_activity": "最後動態", + "two_factor": "雙重認證 (2FA)", + "two_factor_enabled": "已啟用", + "two_factor_disabled": "已停用", + "logout": "登出", + "export_friend_list": "匯出好友列表", + "export_own_avatars": "匯出私有角色", + "discord_names": "Discord 名稱", + "export_notes": "匯出備註" + }, + "game_info": { + "header": "遊戲資訊", + "online_users": "線上玩家", + "user_online": "{count} 位玩家在線上", + "refresh": "點擊以重新整理" + }, + "vrc_sdk_downloads": { + "header": "下載 VRC SDK" + }, + "direct_access": { + "header": "直接存取", + "username": "玩家名稱", + "user_id": "玩家 ID", + "world_instance": "世界 / 房間", + "avatar": "角色" + }, + "invite_messages": "邀請訊息", + "invite_response_messages": "邀請回覆訊息", + "invite_request_messages": "邀請請求訊息", + "invite__request_response_messages": "邀請請求回覆訊息", + "past_display_names": "過去顯示名稱", + "config_json": "JSON 資料", + "current_user_json": "目前玩家的 JSON 資料", + "refresh_tooltip": "重新整理", + "clear_results_tooltip": "清除結果" + }, + "settings": { + "header": "設定", + "category": { + "general": "一般", + "appearance": "外觀", + "notifications": "通知", + "wrist_overlay": "手腕疊層", + "discord_presence": "Discord 遊戲動態", + "advanced": "進階" + }, + "general": { + "general": { + "header": "一般", + "version": "版本", + "latest_app_version": "最新版本", + "latest_app_version_refresh": "點擊以重新整理", + "repository_url": "原始碼連結", + "support": "支援" + }, + "vrcx_updater": { + "header": "VRCX 更新器", + "change_build": "變更版本", + "auto_update": "自動更新", + "auto_update_off": "關閉", + "auto_update_notify": "通知", + "auto_update_download": "自動下載", + "auto_update_install": "自動安裝" + }, + "application": { + "header": "應用程式", + "startup": "在 Windows 啟動時啟動", + "minimized": "以最小化啟動", + "tray": "最小化到系統列" + }, + "legal_notice": { + "header": "法律聲明", + "info": "VRCX 是一個提供好友管理的輔助應用程式。這個程式使用非官方的 VRChat API (VRCSDK)。", + "disclaimer1": "VRCX 不受 VRChat 的認可,也不反應 VRChat 或任何正式參與製作或管理 VRChat 的觀點或意見。VRChat 是 VRChat Inc. 的商標。 VRChat © VRChat Inc.", + "disclaimer2": "pypy 和 Natsumi 將不對使用 VRCX 引起的任何問題負責。使用時請自負風險!", + "open_source_software_notice": "開放原始碼軟體授權條款" + } + }, + "appearance": { + "appearance": { + "header": "外觀", + "theme_mode": "主題", + "theme_mode_system": "系統", + "theme_mode_light": "淺色", + "theme_mode_dark": "深色", + "vrcplus_profile_icons": "VRChat+ 個人檔案圖示", + "disable_tooltips": "關閉提示", + "sort_favorite_by": "最愛排序依據", + "sort_favorite_by_name": "名稱", + "sort_favorite_by_date": "時間", + "sort_instance_users_by": "坊間玩家排序依據", + "sort_instance_users_by_time": "時間", + "sort_instance_users_by_alphabet": "字母順序", + "table_max_size": "表格大小", + "page_size": "頁面大小:" + }, + "timedate": { + "header": "時間 / 日期", + "time_format": "時間格式", + "time_format_24": "24 小時制", + "time_format_12": "12 小時制", + "force_iso_date_format": "強制使用 ISO 時間格式" + }, + "side_panel": { + "header": "側板", + "sorting": { + "header": "排序", + "sort_private_to_bottom": "將 私人世界 排序到底部", + "sort_by_status": "依狀態排序", + "sort_gps_to_top": "將 GPS 排序到頂部", + "sort_gps_to_top_notice": "(僅限上線玩家)", + "sort_favorite_by": "最愛玩家 排序依據", + "sort_favorite_by_alphabet": "字母順序", + "sort_favorite_by_online_time": "上線時長", + "sort_online_by": "網頁玩家 排序依據", + "sort_online_by_alphabet": "字母順序", + "sort_online_by_online_time": "上線時長", + "sort_active_by": "上線玩家 排序依據", + "sort_active_by_alphabet": "字母順序", + "sort_active_by_online_time": "上線時長", + "sort_offline_by": "離線玩家 排序依據", + "sort_offline_by_alphabet": "字母順序", + "sort_offline_by_offline_time": "離線時長" + }, + "width": "寬度" + }, + "user_dialog": { + "header": "玩家資訊", + "hide_vrchat_notes": "隱藏 VRChat 備註", + "hide_vrcx_memos": "隱藏 VRCX 備忘錄", + "export_vrcx_memos_into_vrchat_notes": "將 VRCX 備忘錄匯出成 VRChat 備註", + "export_notes": "匯出備註" + }, + "user_colors": { + "header": "玩家名稱顏色", + "random_colors_from_user_id": "從玩家 ID 隨機挑選顏色" + } + }, + "notifications": { + "notifications": { + "header": "通知", + "notification_filter": "通知篩選器", + "steamvr_notifications": { + "header": "SteamVR 通知", + "steamvr_overlay": "SteamVR 疊層", + "overlay_notifications": "疊層通知", + "notification_position": "通知位置", + "xsoverlay_notifications": "XSOverlay 通知", + "user_images": "玩家照片(較慢)", + "notification_timeout": "通知時長" + }, + "desktop_notifications": { + "header": "桌面通知", + "when_to_display": "顯示時機", + "when_to_display_never": "永不", + "when_to_display_desktop": "在桌面模式時", + "when_to_display_inside_vr": "在 VR 裡時", + "when_to_display_outside_vr": "在 VR 外時", + "when_to_display_game_closed": "遊戲關閉時", + "when_to_display_game_running": "遊戲執行中", + "when_to_display_always": "總是" + }, + "text_to_speech": { + "header": "文字轉語音選項", + "when_to_play": "通知文字轉語音播放時機", + "when_to_play_never": "永不", + "when_to_play_inside_vr": "在 VR 裡時", + "when_to_play_game_closed": "遊戲關閉時", + "when_to_play_game_running": "遊戲執行中", + "when_to_play_always": "總是", + "tts_voice": "語音樣式" + } + } + }, + "wrist_overlay": { + "steamvr_wrist_overlay": { + "header": "SteamVR 手腕疊層", + "description": "* 當 VRChat 開啟時它會自動開啟", + "grip": "握持:Vive 或其它控制器的握持鍵、Oculus X/A 按鍵", + "menu": "選單:Vive 選單鍵、Index B、Oculus Y/B 按鍵", + "steamvr_overlay": "SteamVR 疊層", + "wrist_feed_overlay": "手腕動態疊層", + "hide_private_worlds": "隱藏私人世界", + "start_overlay_with": "啟動時一併啟動", + "overlay_button": "疊層按鍵", + "overlay_button_grip": "握持", + "overlay_button_menu": "選單", + "display_overlay_on": "疊層顯示位置", + "display_overlay_on_left": "左手", + "display_overlay_on_right": "右手", + "display_overlay_on_both": "雙手", + "background_color": "背景顏色", + "minimal_feed_icons": "迷你動態圖示", + "hide_vr_devices": "隱藏 VR 裝置", + "hide_cpu_usage": "隱藏 CPU 使用率", + "hide_game_uptime": "隱藏啟動時長", + "show_pc_uptime": "顯示電腦啟動時長", + "wrist_feed_filters": "手腕動態篩選器" + } + }, + "discord_presence": { + "discord_presence": { + "header": "Discord 遊戲動態", + "description": "* 僅在 VRChat 開啟時有效", + "enable": "啟用", + "enable_tooltip": "建議在 VRChat config.json 中停用原生 Discord 遊戲動態來防止衝突", + "instance_type_player_count": "房間種類 / 玩家人數", + "join_button": "加入按鈕(僅限公開房間)", + "hide_details_in_private": "在私人房間時隱藏世界資訊", + "hide_images": "隱藏世界縮圖" + } + }, + "advanced": { + "advanced": { + "header": "進階設定", + "launch_options": "啟動選項", + "pending_offline": { + "header": "待確認離線", + "description": "將玩家標記為離線之前延遲(防止誤判)", + "set_delay": "設定延遲" + }, + "primary_password": { + "header": "主密碼", + "description": "密碼加密(將停用自動登入)" + }, + "vrchat_quit_fix": { + "header": "VRChat 關閉修正", + "description": "在離開遊戲時強制停止 VRChat" + }, + "auto_cache_management": { + "header": "關閉 VRChat 時自動管理快取", + "description": "自動從快取中刪除舊版本" + }, + "remote_database": { + "header": "遠端角色資料庫", + "enable": "啟用", + "avatar_database_provider": "角色資料庫提供方" + }, + "youtube_api": { + "header": "Youtube API", + "enable": "啟用", + "youtube_api_key": "Youtube API 金鑰" + }, + "video_progress_pie": { + "header": "影片進度圓餅疊層", + "enable": "啟用", + "enable_tooltip": "需要啟用 SteamVR 疊層選項", + "dance_world_only": "僅限跳舞世界" + }, + "cache_debug": { + "header": "VRCX 世界快取/除錯", + "disable_gamelog": "關閉遊戲紀錄", + "disable_gamelog_notice": "(可能會弄壞很多東西)", + "user_cache": "玩家快取:", + "world_cache": "世界快取:", + "avatar_cache": "角色快取:", + "avatar_name_cache": "角色名稱快取:", + "clear_cache": "清除快取", + "auto_clear_cache": "自動清除快取", + "download_history": "下載紀錄", + "show_console": "顯示主控台" + }, + "sqlite_table_size": { + "header": "SQLite 數據表大小", + "refresh": "重新整理", + "gps": "GPS:", + "status": "狀態:", + "bio": "自我介紹:", + "avatar": "角色:", + "online_offline": "上線 / 離線:", + "friend_log_history": "好友歷史紀錄:", + "notification": "通知:", + "location": "位置:", + "join_leave": "加入 / 離開:", + "portal_spawn": "開啟傳送門:", + "video_play": "影片播放:", + "event": "事件:" + } + }, + "photon": { + "header": "Photon 紀錄疊層", + "event_hud": { + "header": "Photon 事件 HUD", + "enable": "啟用", + "enable_tooltip": "需要啟用 SteamVR 疊層選項", + "filter": "篩選器", + "filter_favorites": "最愛", + "filter_friends": "好友", + "filter_everyone": "所有人", + "message_timeout": "訊息時長" + }, + "event_hud": { + "header": "玩家愈時 HUD", + "enable": "啟用", + "enable_tooltip": "需要啟用 SteamVR 疊層選項", + "filter": "篩選器", + "filter_favorites": "最愛", + "filter_friends": "好友", + "filter_everyone": "所有人", + "timeout_threshold": "愈時閾值" + } + } + } + } + }, + "side_panel": { + "search_placeholder": "搜尋", + "search_result_active": "活躍", + "search_result_offline": "離線", + "search_result_more": "搜尋更多:", + "direct_access_tooltip": "直接存取解貼簿的 ID / 連結", + "refresh_tooltip": "重新整理好友", + "friends": "好友", + "me": "我", + "favorite": "最愛", + "online": "上線", + "active": "活躍", + "offline": "離線", + "penfing_offline": "待確認離線" + }, + "dialog": { + "user": { + "status": { + "active": "活躍", + "offline": "離線", + "online": "上線", + "join_me": "加入我", + "ask_me": "詢問我", + "busy": "請勿打擾" + }, + "previous_display_names": "過去的顯示名稱:", + "tags": { + "friend_no": "第 {number} 位好友", + "vrchat_team": "VRChat 團隊" + }, + "actions": { + "favorite_tooltip": "添加到我的最愛", + "unfavorite_tooltip": "從我的最愛中移除", + "refresh": "重新整理", + "copy_url": "複製玩家連結", + "invite": "邀請", + "invite_with_message": "邀請(訊息)", + "request_invite": "請求邀請", + "request_invite_with_message": "請求邀請(訊息)", + "invite_to_group": "邀情到群組", + "manage_gallery_icon": "管理相簿 / 圖示", + "accept_friend_request": "接受好友邀請", + "deny_friend_request": "回絕好友邀請", + "cancel_friend_request": "取消好友邀請", + "send_friend_request": "傳送好友邀請", + "show_avatar_author": "顯示角色作者", + "show_fallback_avatar": "顯示備用角色資訊", + "show_previous_instances": "顯示過去的房間", + "show_previous_images": "顯示角色以前的圖片", + "moderation_block": "封鎖", + "moderation_unblock": "解除封鎖", + "moderation_mute": "靜音", + "moderation_unmute": "解除靜音", + "moderation_hide_avatar": "顯示角色", + "moderation_show_avatar": "隱藏角色", + "moderation_enable_avatar_interaction": "開啟角色互動", + "moderation_disable_avatar_interaction": "關閉角色互動", + "edit_status": "社交狀態", + "edit_language": "語言", + "edit_bio": "自我介紹", + "unfriend": "解除好友", + "logout": "登出" + }, + "info": { + "header": "資訊", + "launch_invite_tooltip": "啟動 / 邀請", + "self_invite_tooltip": "自我邀請", + "refresh_user_count_tooltip": "重新整理房間人數", + "instance_creator": "房間建立者", + "note": "備註", + "note_placeholder": "點擊添加備註", + "memo": "備忘錄", + "memo_placeholder": "點擊添加備忘錄", + "avatar_info": "角色資訊", + "avatar_info_last_seen": "最後已知角色資訊", + "represented_group": "代表群組", + "bio": "自我介紹", + "last_seen": "最後上線", + "join_count": "加入次數", + "time_together": "一起遊玩時長", + "online_for": "上線時長", + "offline_for": "離線時長", + "last_activity": "最後動態", + "last_login": "最後登入", + "date_joined": "加入時間", + "friended": "好友", + "unfriended": "解除好友", + "avatar_cloning": "角色複製", + "avatar_cloning_allow": "允許", + "avatar_cloning_deny": "不允許", + "home_location": "家點", + "accuracy_notice": "本地資料庫的資料可能不精確" + }, + "groups": { + "header": "群組", + "total_count": "總共 {count}", + "own_groups": "擁有群組", + "mutual_groups": "共同群組", + "groups": "群組" + }, + "worlds": { + "header": "世界", + "total_count": "總共 {count}", + "sort_by_name": "依名稱排序", + "sort_by_update": "依更新排序" + }, + "favorite_worlds": { + "header": "最愛世界" + }, + "avatars": { + "header": "角色", + "total_count": "總共 {count}", + "sort_by_name": "依名稱排序", + "sort_by_update": "依更新排序", + "all": "所有", + "public": "公開", + "private": "私人" + }, + "json": { + "header": "原始資料" + } + }, + "world": { + "tags": { + "public": "公開", + "private": "私人", + "labs": "社區實驗室", + "cache": "快取" + }, + "actions": { + "delete_cache_tooltip": "從快取中刪除世界", + "favorite_tooltip": "添加到我的最愛", + "unfavorite_tooltip": "從我的最愛中移除", + "refresh": "重新整理", + "new_instance": "新房間", + "make_home": "設為家點", + "reset_home": "重設家點", + "show_previous_instances": "顯示過去的房間", + "show_previous_images": "顯示過去的圖片", + "rename": "重新命名", + "change_description": "變更敘述", + "change_capacity": "變更最大玩家上限", + "change_preview": "變更 YouTube 預覽", + "change_tags": "變更標籤", + "change_image": "變更圖片", + "download_package": "下載 Unity Package", + "publish_to_labs": "發佈到社區實驗室", + "unpublish": "取消發佈", + "delete": "刪除" + }, + "instances": { + "header": "房間", + "public_count": "公開 {count}", + "private_count": "私人 {count}", + "capacity_count": "玩家上限 {count} ({max})", + "self_invite_tooltip": "自我邀請", + "refresh_user_count_tooltip": "重新整理房間人數", + "instance_creator": "房間建立者" + }, + "info": { + "header": "資訊", + "id": "世界 ID", + "id_tooltip": "複製到剪貼簿", + "copy_id": "複製 ID", + "copy_url": "複製連結", + "youtube_preview": "YouTube 預覽", + "players": "玩家人數", + "favorites": "最愛次數", + "visits": "總綁訪次數", + "capacity": "最大玩家上限", + "heat": "熱度", + "popularity": "熱門度", + "created_at": "創建時間", + "last_updated": "最後更新", + "version": "版本", + "platform": "平台", + "last_visited": "上次拜訪", + "visit_count": "我綁訪次數", + "time_spent": "停留時長", + "accuracy_notice": "本地資料庫的資料可能不精確" + }, + "json": { + "header": "原始資料" + } + }, + "avatar": { + "header": "角色", + "tags": { + "public": "公開", + "private": "私人", + "fallback": "備用", + "cache": "快取" + }, + "actions": { + "delete_cache_tooltip": "從快取中刪除角色", + "favorite_tooltip": "添加到我的最愛", + "unfavorite_tooltip": "從我的最愛中移除", + "refresh": "重新整理", + "select": "選擇角色", + "select_fallback": "選擇為備用角色", + "block": "封鎖角色", + "unblock": "解除封鎖角色", + "show_previous_images": "顯示過去的圖片", + "make_public": "設為公開", + "make_private": "設為私人", + "rename": "重新命名", + "change_description": "變更敘述", + "change_image": "變更圖片", + "download_package": "下載 Unity Package", + "delete": "刪除" + }, + "info": { + "header": "資訊", + "id": "角色 ID", + "id_tooltip": "複製到剪貼簿", + "copy_id": "複製 ID", + "copy_url": "複製連結", + "created_at": "創建時間", + "last_updated": "最後更新", + "version": "版本", + "platform": "平台" + }, + "json": { + "header": "原始資料" + } + }, + "group": { + "tags": { + "verified": "已認證", + "public": "公開", + "private": "私人", + "open": "開放", + "request": "請求", + "invite": "邀請", + "closed": "關閉", + "joined": "已加入", + "banned": "已封鎖", + "visible": "能見度:所有人", + "friends": "能見度:好友", + "hidden": "能見度:隱藏", + "subscribed": "已訂閱公告" + }, + "actions": { + "represent_tooltip": "顯示在個人檔案上", + "unrepresent_tooltip": "停止顯示在個人檔案上", + "cancel_join_request_tooltip": "取消加入請求", + "pending_request_tooltip": "待接受邀請", + "request_join_tooltip": "清求加入", + "invite_required_tooltip": "需要被邀請才能加入", + "join_group_tooltip": "加入群組", + "refresh": "重新整理", + "unsubscribe": "取消訂閱公告", + "subscribe": "訂閱公告", + "invite_to_group": "邀請到群組", + "visibility_everyone": "能見度:所有人", + "visibility_friends": "能見度:好友", + "visibility_hidden": "能見度:隱藏", + "leave": "離開群組" + }, + "info": { + "header": "資訊", + "announcement": "公告", + "rules": "規則", + "members": "成員", + "created_at": "創建時間", + "links": "連結", + "url": "群組連結", + "url_tooltip": "複製連結到剪貼簿", + "id": "群組 ID", + "id_tooltip": "複製 ID 到剪貼簿", + "joined_at": "加入時間", + "roles": "身分", + "role_description": "敘述:", + "role_updated_at": "更新時間:", + "role_created_at": "創建時間:", + "role_permissions": "權限:" + }, + "members": { + "header": "成員", + "all_members": "所有成員", + "friends_only": "好友", + "load_more": "載入更多……" + }, + "json": { + "header": "原始資料" + } + }, + "social_status": { + "header": "社交狀態", + "history": "過去的社交狀態", + "status_placeholder": "今天心情如何?", + "update": "更新" + }, + "language": { + "header": "語言", + "add_language": "新增語言", + "select_language": "選擇語言", + "ok": "確定", + "cancel": "取消" + }, + "bio": { + "header": "自我介紹", + "bio_placeholder": "在這裡介紹一下自己吧!", + "add_link": "新增社交連結", + "update": "更新" + } + }, + "table": { + "feed": { + "date": "時間", + "type": "類型", + "user": "玩家", + "detail": "詳細" + }, + "gameLog": { + "date": "時間", + "type": "類型", + "user": "玩家", + "detail": "詳細" + }, + "playerList": { + "avatar": "角色", + "timer": "時長", + "photonId": "Photon ID", + "icon": "圖示", + "platform": "平台", + "displayName": "顯示名稱", + "status": "狀態", + "rank": "階級", + "language": "語言", + "bioLink": "社交連結" + }, + "friendLog": { + "date": "時間", + "type": "類型", + "user": "玩家", + "action": "動作" + }, + "moderation": { + "date": "時間", + "type": "類型", + "source": "來源", + "target": "目標", + "action": "動作" + }, + "notification": { + "date": "時間", + "type": "類型", + "user": "玩家", + "photo": "照片", + "message": "訊息", + "action": "動作" + }, + "friendList": { + "no": "No.", + "avatar": "角色", + "displayName": "顯示名稱", + "rank": "階級", + "status": "狀態", + "language": "語言", + "bioLink": "社交連結", + "joinCount": "加入次數", + "timeTogether": "一起遊玩時長", + "lastSeen": "最後上線", + "lastActivity": "最後活動", + "lastLogin": "最後登入", + "dateJoined": "加入時間", + "unfriend": "解除好友" + }, + "social_status": { + "no": "No.", + "status": "狀蓋" + } + } +} \ No newline at end of file