mirror of
https://codeberg.org/Hyperpipe/Hyperpipe
synced 2025-06-27 20:58:01 +02:00
Changes:
- Closes #9 - Removed dependency on vue-i18n - Localization Changes
This commit is contained in:
parent
44db54737b
commit
fcc3d455c6
18 changed files with 143 additions and 270 deletions
128
package-lock.json
generated
128
package-lock.json
generated
|
@ -17,7 +17,6 @@
|
||||||
"shaka-player": "^4.2.1",
|
"shaka-player": "^4.2.1",
|
||||||
"stream-browserify": "^3.0.0",
|
"stream-browserify": "^3.0.0",
|
||||||
"vue": "^3.2.38",
|
"vue": "^3.2.38",
|
||||||
"vue-i18n": "^9.2.2",
|
|
||||||
"xml-js": "^1.6.11"
|
"xml-js": "^1.6.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -64,63 +63,6 @@
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@intlify/core-base": {
|
|
||||||
"version": "9.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.2.2.tgz",
|
|
||||||
"integrity": "sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==",
|
|
||||||
"dependencies": {
|
|
||||||
"@intlify/devtools-if": "9.2.2",
|
|
||||||
"@intlify/message-compiler": "9.2.2",
|
|
||||||
"@intlify/shared": "9.2.2",
|
|
||||||
"@intlify/vue-devtools": "9.2.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@intlify/devtools-if": {
|
|
||||||
"version": "9.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.2.2.tgz",
|
|
||||||
"integrity": "sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@intlify/shared": "9.2.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@intlify/message-compiler": {
|
|
||||||
"version": "9.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.2.2.tgz",
|
|
||||||
"integrity": "sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==",
|
|
||||||
"dependencies": {
|
|
||||||
"@intlify/shared": "9.2.2",
|
|
||||||
"source-map": "0.6.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@intlify/shared": {
|
|
||||||
"version": "9.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.2.2.tgz",
|
|
||||||
"integrity": "sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@intlify/vue-devtools": {
|
|
||||||
"version": "9.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.2.2.tgz",
|
|
||||||
"integrity": "sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@intlify/core-base": "9.2.2",
|
|
||||||
"@intlify/shared": "9.2.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@swc/helpers": {
|
"node_modules/@swc/helpers": {
|
||||||
"version": "0.3.17",
|
"version": "0.3.17",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.3.17.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.3.17.tgz",
|
||||||
|
@ -1147,23 +1089,6 @@
|
||||||
"@vue/shared": "3.2.39"
|
"@vue/shared": "3.2.39"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vue-i18n": {
|
|
||||||
"version": "9.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.2.2.tgz",
|
|
||||||
"integrity": "sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"@intlify/core-base": "9.2.2",
|
|
||||||
"@intlify/shared": "9.2.2",
|
|
||||||
"@intlify/vue-devtools": "9.2.2",
|
|
||||||
"@vue/devtools-api": "^6.2.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 14"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"vue": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/webrtc-adapter": {
|
"node_modules/webrtc-adapter": {
|
||||||
"version": "7.7.1",
|
"version": "7.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-7.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-7.7.1.tgz",
|
||||||
|
@ -1210,48 +1135,6 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@intlify/core-base": {
|
|
||||||
"version": "9.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.2.2.tgz",
|
|
||||||
"integrity": "sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==",
|
|
||||||
"requires": {
|
|
||||||
"@intlify/devtools-if": "9.2.2",
|
|
||||||
"@intlify/message-compiler": "9.2.2",
|
|
||||||
"@intlify/shared": "9.2.2",
|
|
||||||
"@intlify/vue-devtools": "9.2.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@intlify/devtools-if": {
|
|
||||||
"version": "9.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.2.2.tgz",
|
|
||||||
"integrity": "sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==",
|
|
||||||
"requires": {
|
|
||||||
"@intlify/shared": "9.2.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@intlify/message-compiler": {
|
|
||||||
"version": "9.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.2.2.tgz",
|
|
||||||
"integrity": "sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==",
|
|
||||||
"requires": {
|
|
||||||
"@intlify/shared": "9.2.2",
|
|
||||||
"source-map": "0.6.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@intlify/shared": {
|
|
||||||
"version": "9.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.2.2.tgz",
|
|
||||||
"integrity": "sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q=="
|
|
||||||
},
|
|
||||||
"@intlify/vue-devtools": {
|
|
||||||
"version": "9.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.2.2.tgz",
|
|
||||||
"integrity": "sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==",
|
|
||||||
"requires": {
|
|
||||||
"@intlify/core-base": "9.2.2",
|
|
||||||
"@intlify/shared": "9.2.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@swc/helpers": {
|
"@swc/helpers": {
|
||||||
"version": "0.3.17",
|
"version": "0.3.17",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.3.17.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.3.17.tgz",
|
||||||
|
@ -1873,17 +1756,6 @@
|
||||||
"@vue/shared": "3.2.39"
|
"@vue/shared": "3.2.39"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"vue-i18n": {
|
|
||||||
"version": "9.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.2.2.tgz",
|
|
||||||
"integrity": "sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==",
|
|
||||||
"requires": {
|
|
||||||
"@intlify/core-base": "9.2.2",
|
|
||||||
"@intlify/shared": "9.2.2",
|
|
||||||
"@intlify/vue-devtools": "9.2.2",
|
|
||||||
"@vue/devtools-api": "^6.2.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"webrtc-adapter": {
|
"webrtc-adapter": {
|
||||||
"version": "7.7.1",
|
"version": "7.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-7.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-7.7.1.tgz",
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
"shaka-player": "^4.2.1",
|
"shaka-player": "^4.2.1",
|
||||||
"stream-browserify": "^3.0.0",
|
"stream-browserify": "^3.0.0",
|
||||||
"vue": "^3.2.38",
|
"vue": "^3.2.38",
|
||||||
"vue-i18n": "^9.2.2",
|
|
||||||
"xml-js": "^1.6.11"
|
"xml-js": "^1.6.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
10
src/App.vue
10
src/App.vue
|
@ -18,15 +18,15 @@ import Prefs from '@/components/Prefs.vue';
|
||||||
|
|
||||||
/* Composables */
|
/* Composables */
|
||||||
import { useStore } from '@/scripts/util.js';
|
import { useStore } from '@/scripts/util.js';
|
||||||
import { useT, useSetupLocale } from '@/scripts/i18n.js';
|
|
||||||
import { useSetupDB, useUpdatePlaylist } from '@/scripts/db.js';
|
import { useSetupDB, useUpdatePlaylist } from '@/scripts/db.js';
|
||||||
|
|
||||||
/* Stores */
|
/* Stores */
|
||||||
import { useData, usePlayer } from '@/stores/player.js';
|
import { useData, usePlayer } from '@/stores/player.js';
|
||||||
import { useResults, useArtist } from '@/stores/results.js';
|
import { useResults, useArtist } from '@/stores/results.js';
|
||||||
import { useNav } from '@/stores/misc.js';
|
import { useNav, useI18n } from '@/stores/misc.js';
|
||||||
|
|
||||||
const store = useStore(),
|
const { t, setupLocale } = useI18n(),
|
||||||
|
store = useStore(),
|
||||||
data = useData(),
|
data = useData(),
|
||||||
player = usePlayer(),
|
player = usePlayer(),
|
||||||
results = useResults(),
|
results = useResults(),
|
||||||
|
@ -101,7 +101,7 @@ onBeforeMount(() => {
|
||||||
|
|
||||||
/* Set the default locale if set */
|
/* Set the default locale if set */
|
||||||
if (store.locale) {
|
if (store.locale) {
|
||||||
useSetupLocale(store.locale);
|
setupLocale(store.locale);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ onMounted(() => {
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main class="placeholder" :data-placeholder="useT('info.search')">
|
<main class="placeholder" :data-placeholder="t('info.search')">
|
||||||
<KeepAlive>
|
<KeepAlive>
|
||||||
<Search v-if="nav.state.page == 'home'" @play-urls="playList" />
|
<Search v-if="nav.state.page == 'home'" @play-urls="playList" />
|
||||||
</KeepAlive>
|
</KeepAlive>
|
||||||
|
|
|
@ -181,6 +181,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
|
padding: 1px 6px;
|
||||||
border: none;
|
border: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
|
|
|
@ -5,12 +5,13 @@ import { useResults } from '@/stores/results.js';
|
||||||
|
|
||||||
import { getJsonHyp } from '@/scripts/fetch.js';
|
import { getJsonHyp } from '@/scripts/fetch.js';
|
||||||
import { useRoute } from '@/scripts/util.js';
|
import { useRoute } from '@/scripts/util.js';
|
||||||
import { useT } from '@/scripts/i18n.js';
|
import { useI18n } from '@/stores/misc.js';
|
||||||
|
|
||||||
import AlbumItem from './AlbumItem.vue';
|
import AlbumItem from './AlbumItem.vue';
|
||||||
|
|
||||||
const props = defineProps(['id']),
|
const props = defineProps(['id']),
|
||||||
{ getAlbum } = useResults();
|
{ getAlbum } = useResults(),
|
||||||
|
{ t } = useI18n();
|
||||||
|
|
||||||
const data = reactive({
|
const data = reactive({
|
||||||
title: '',
|
title: '',
|
||||||
|
@ -57,12 +58,12 @@ onMounted(get);
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<template v-if="data.title">
|
<template v-if="data.title">
|
||||||
<i class="bi bi-arrow-left back" @click="get"> {{ useT('action.back') }}</i>
|
<i class="bi bi-arrow-left back" @click="get"> {{ t('action.back') }}</i>
|
||||||
|
|
||||||
<h2 class="head">{{ data.title }}</h2>
|
<h2 class="head">{{ data.title }}</h2>
|
||||||
|
|
||||||
<template v-for="type in ['featured', 'spotlight', 'community']">
|
<template v-for="type in ['featured', 'spotlight', 'community']">
|
||||||
<h3 class="head">{{ useT('title.' + type) }}</h3>
|
<h3 class="head">{{ t('title.' + type) }}</h3>
|
||||||
<div class="grid-3">
|
<div class="grid-3">
|
||||||
<template v-for="i in data[type]">
|
<template v-for="i in data[type]">
|
||||||
<AlbumItem
|
<AlbumItem
|
||||||
|
@ -79,7 +80,7 @@ onMounted(get);
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<h2 v-if="btns.moods.length > 0">{{ useT('title.moods') }}</h2>
|
<h2 v-if="btns.moods.length > 0">{{ t('title.moods') }}</h2>
|
||||||
|
|
||||||
<div class="btn-grid">
|
<div class="btn-grid">
|
||||||
<button
|
<button
|
||||||
|
@ -91,7 +92,7 @@ onMounted(get);
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 v-if="btns.genres.length > 0">{{ useT('title.genres') }}</h2>
|
<h2 v-if="btns.genres.length > 0">{{ t('title.genres') }}</h2>
|
||||||
|
|
||||||
<div class="btn-grid">
|
<div class="btn-grid">
|
||||||
<button
|
<button
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useT } from '@/scripts/i18n.js';
|
import { useI18n } from '@/stores/misc.js';
|
||||||
|
|
||||||
import TextModal from './TextModal.vue';
|
import TextModal from './TextModal.vue';
|
||||||
|
|
||||||
defineProps(['text']);
|
defineProps(['text']);
|
||||||
|
|
||||||
const parse = d =>
|
const { t } = useI18n(),
|
||||||
new DOMParser().parseFromString(d, 'text/html').body.innerText;
|
parse = d => new DOMParser().parseFromString(d, 'text/html').body.innerText;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<TextModal>
|
<TextModal>
|
||||||
<template #content>
|
<template #content>
|
||||||
<pre class="placeholder" :data-placeholder="useT('info.no_info')">{{
|
<pre class="placeholder" :data-placeholder="t('info.no_info')">{{
|
||||||
text ? parse(text.replaceAll('<br>', '\n')) : ''
|
text ? parse(text.replaceAll('<br>', '\n')) : ''
|
||||||
}}</pre>
|
}}</pre>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -3,11 +3,12 @@ import { ref, watch } from 'vue';
|
||||||
|
|
||||||
import { getJsonHyp } from '@/scripts/fetch.js';
|
import { getJsonHyp } from '@/scripts/fetch.js';
|
||||||
import { useData } from '@/stores/player.js';
|
import { useData } from '@/stores/player.js';
|
||||||
import { useT } from '@/scripts/i18n.js';
|
import { useI18n } from '@/stores/misc.js';
|
||||||
|
|
||||||
import TextModal from './TextModal.vue';
|
import TextModal from './TextModal.vue';
|
||||||
|
|
||||||
const data = useData(),
|
const { t } = useI18n(),
|
||||||
|
data = useData(),
|
||||||
text = ref(''),
|
text = ref(''),
|
||||||
source = ref(''),
|
source = ref(''),
|
||||||
status = ref(false);
|
status = ref(false);
|
||||||
|
@ -51,8 +52,8 @@ watch(
|
||||||
class="placeholder"
|
class="placeholder"
|
||||||
:data-placeholder="
|
:data-placeholder="
|
||||||
data.state.urls[0]?.url && !status
|
data.state.urls[0]?.url && !status
|
||||||
? useT('info.lyrics.load')
|
? t('lyrics.load')
|
||||||
: useT('info.lyrics.void')
|
: t('lyrics.void')
|
||||||
"
|
"
|
||||||
>{{ text }}</pre
|
>{{ text }}</pre
|
||||||
>
|
>
|
||||||
|
|
|
@ -7,7 +7,7 @@ import Modal from './Modal.vue';
|
||||||
import { useRand } from '@/scripts/colors.js';
|
import { useRand } from '@/scripts/colors.js';
|
||||||
import { useStore } from '@/scripts/util.js';
|
import { useStore } from '@/scripts/util.js';
|
||||||
import { getJsonAuth, getAuthPlaylists } from '@/scripts/fetch.js';
|
import { getJsonAuth, getAuthPlaylists } from '@/scripts/fetch.js';
|
||||||
import { useT } from '@/scripts/i18n.js';
|
import { useI18n } from '@/stores/misc.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useListPlaylists,
|
useListPlaylists,
|
||||||
|
@ -16,7 +16,8 @@ import {
|
||||||
useUpdatePlaylist,
|
useUpdatePlaylist,
|
||||||
} from '../scripts/db.js';
|
} from '../scripts/db.js';
|
||||||
|
|
||||||
const store = useStore(),
|
const { t } = useI18n(),
|
||||||
|
store = useStore(),
|
||||||
auth = ref(!!store.auth);
|
auth = ref(!!store.auth);
|
||||||
|
|
||||||
const emit = defineEmits(['play-urls', 'open-playlist']),
|
const emit = defineEmits(['play-urls', 'open-playlist']),
|
||||||
|
@ -202,7 +203,7 @@ onMounted(async () => {
|
||||||
<Modal
|
<Modal
|
||||||
n="2"
|
n="2"
|
||||||
:display="show.new"
|
:display="show.new"
|
||||||
:title="useT('playlist.create')"
|
:title="t('playlist.create')"
|
||||||
@show="
|
@show="
|
||||||
e => {
|
e => {
|
||||||
show.new = e;
|
show.new = e;
|
||||||
|
@ -211,10 +212,10 @@ onMounted(async () => {
|
||||||
<template #content>
|
<template #content>
|
||||||
<div v-if="auth" class="tabs">
|
<div v-if="auth" class="tabs">
|
||||||
<button :data-active="!user.create" @click="user.create = false">
|
<button :data-active="!user.create" @click="user.create = false">
|
||||||
{{ useT('title.local') }}
|
{{ t('title.local') }}
|
||||||
</button>
|
</button>
|
||||||
<button :data-active="user.create" @click="user.create = true">
|
<button :data-active="user.create" @click="user.create = true">
|
||||||
{{ useT('title.remote') }}
|
{{ t('title.remote') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -225,9 +226,9 @@ onMounted(async () => {
|
||||||
v-model="text" />
|
v-model="text" />
|
||||||
</template>
|
</template>
|
||||||
<template #buttons>
|
<template #buttons>
|
||||||
<button @click="show.new = false">{{ useT('action.cancel') }}</button>
|
<button @click="show.new = false">{{ t('action.cancel') }}</button>
|
||||||
<button @click="user.create ? createPlaylist() : Create()">
|
<button @click="user.create ? createPlaylist() : Create()">
|
||||||
{{ useT('action.create') }}
|
{{ t('action.create') }}
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -235,7 +236,7 @@ onMounted(async () => {
|
||||||
<Modal
|
<Modal
|
||||||
:n="sync.type == 'send' ? 2 : 1"
|
:n="sync.type == 'send' ? 2 : 1"
|
||||||
:display="show.sync"
|
:display="show.sync"
|
||||||
:title="useT('playlist.sync')"
|
:title="t('playlist.sync')"
|
||||||
@show="
|
@show="
|
||||||
e => {
|
e => {
|
||||||
show.sync = e;
|
show.sync = e;
|
||||||
|
@ -246,10 +247,10 @@ onMounted(async () => {
|
||||||
<button
|
<button
|
||||||
:data-active="sync.type == 'send'"
|
:data-active="sync.type == 'send'"
|
||||||
@click="sync.type = 'send'">
|
@click="sync.type = 'send'">
|
||||||
{{ useT('action.send') }}
|
{{ t('action.send') }}
|
||||||
</button>
|
</button>
|
||||||
<button :data-active="sync.type == 'rec'" @click="sync.type = 'rec'">
|
<button :data-active="sync.type == 'rec'" @click="sync.type = 'rec'">
|
||||||
{{ useT('action.receive') }}
|
{{ t('action.receive') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -267,11 +268,9 @@ onMounted(async () => {
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #buttons>
|
<template #buttons>
|
||||||
<button @click="show.sync = false">{{ useT('action.cancel') }}</button>
|
<button @click="show.sync = false">{{ t('action.cancel') }}</button>
|
||||||
<button v-if="sync.type == 'send'" @click="Send">
|
<button v-if="sync.type == 'send'" @click="Send">
|
||||||
{{
|
{{ sync.type == 'send' ? t('action.send') : t('action.recieve') }}
|
||||||
sync.type == 'send' ? useT('action.send') : useT('action.recieve')
|
|
||||||
}}
|
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -284,7 +283,7 @@ onMounted(async () => {
|
||||||
@click="show.sync = true"></div>
|
@click="show.sync = true"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 v-if="list.length > 0">{{ useT('playlist.local') }}</h2>
|
<h2 v-if="list.length > 0">{{ t('playlist.local') }}</h2>
|
||||||
|
|
||||||
<div class="grid-3">
|
<div class="grid-3">
|
||||||
<template v-for="i in list">
|
<template v-for="i in list">
|
||||||
|
@ -296,7 +295,7 @@ onMounted(async () => {
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 class="login-h">{{ useT('playlist.remote') }}</h2>
|
<h2 class="login-h">{{ t('playlist.remote') }}</h2>
|
||||||
|
|
||||||
<div v-if="auth" class="grid-3">
|
<div v-if="auth" class="grid-3">
|
||||||
<template v-for="i in user.playlists">
|
<template v-for="i in user.playlists">
|
||||||
|
@ -321,7 +320,7 @@ onMounted(async () => {
|
||||||
autocomplete="password"
|
autocomplete="password"
|
||||||
@change="user.password = $event.target.value"
|
@change="user.password = $event.target.value"
|
||||||
required />
|
required />
|
||||||
<button @click="Login" class="textbox">{{ useT('title.login') }}</button>
|
<button @click="Login" class="textbox">{{ t('title.login') }}</button>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Don't have an account? register on
|
Don't have an account? register on
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useData, usePlayer } from '@/stores/player.js';
|
import { useData, usePlayer } from '@/stores/player.js';
|
||||||
import { useT } from '@/scripts/i18n.js';
|
import { useI18n } from '@/stores/misc.js';
|
||||||
|
|
||||||
const player = usePlayer(),
|
const { t } = useI18n(),
|
||||||
|
player = usePlayer(),
|
||||||
data = useData();
|
data = useData();
|
||||||
|
|
||||||
defineEmits(['playthis']);
|
defineEmits(['playthis']);
|
||||||
|
@ -10,7 +11,7 @@ defineEmits(['playthis']);
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Transition name="fade">
|
<Transition name="fade">
|
||||||
<div class="pl-modal placeholder" :data-placeholder="useT('playlist.add')">
|
<div class="pl-modal placeholder" :data-placeholder="t('playlist.add')">
|
||||||
<template v-for="plurl in data.state.urls">
|
<template v-for="plurl in data.state.urls">
|
||||||
<div class="pl-item" @click="$emit('playthis', plurl)">
|
<div class="pl-item" @click="$emit('playthis', plurl)">
|
||||||
<span v-if="data.state.url == plurl.url" class="bars-wrap">
|
<span v-if="data.state.url == plurl.url" class="bars-wrap">
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
|
|
||||||
import { getJson } from '@/scripts/fetch.js';
|
import { getJson } from '@/scripts/fetch.js';
|
||||||
import { SUPPORTED_LOCALES, useT, useSetupLocale } from '@/scripts/i18n.js';
|
import { SUPPORTED_LOCALES, useI18n } from '@/stores/misc.js';
|
||||||
import { useStore } from '@/scripts/util.js';
|
import { useStore } from '@/scripts/util.js';
|
||||||
|
|
||||||
const instances = ref([]),
|
const { t, setupLocale } = useI18n(),
|
||||||
|
instances = ref([]),
|
||||||
hypInstances = ref([]),
|
hypInstances = ref([]),
|
||||||
next = ref(false);
|
next = ref(false);
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ function setTheme(theme) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setLang(locale) {
|
function setLang(locale) {
|
||||||
useSetupLocale(locale);
|
setupLocale(locale);
|
||||||
setStore('locale', locale);
|
setStore('locale', locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ onMounted(() => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<h2>{{ useT('pref.theme') }}</h2>
|
<h2>{{ t('pref.theme') }}</h2>
|
||||||
<select
|
<select
|
||||||
id="pref-theme"
|
id="pref-theme"
|
||||||
:value="getTheme()"
|
:value="getTheme()"
|
||||||
|
@ -79,7 +80,7 @@ onMounted(() => {
|
||||||
<option v-for="i in SUPPORTED_LOCALES" :value="i.code">{{ i.name }}</option>
|
<option v-for="i in SUPPORTED_LOCALES" :value="i.code">{{ i.name }}</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<h2>{{ useT('pref.player') }}</h2>
|
<h2>{{ t('pref.player') }}</h2>
|
||||||
|
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<input
|
<input
|
||||||
|
@ -88,11 +89,11 @@ onMounted(() => {
|
||||||
id="pref-chk-next"
|
id="pref-chk-next"
|
||||||
@change="setStore('next', $event.target.checked)"
|
@change="setStore('next', $event.target.checked)"
|
||||||
v-model="next" />
|
v-model="next" />
|
||||||
<label for="pref-chk-next">{{ useT('pref.auto_queue') }}</label>
|
<label for="pref-chk-next">{{ t('pref.auto_queue') }}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<label for="pref-codec">{{ useT('pref.codec') }}</label>
|
<label for="pref-codec">{{ t('pref.codec') }}</label>
|
||||||
<select
|
<select
|
||||||
id="pref-codec"
|
id="pref-codec"
|
||||||
name="pref-codec"
|
name="pref-codec"
|
||||||
|
@ -106,20 +107,20 @@ onMounted(() => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<label for="pref-quality">{{ useT('pref.quality') }}</label>
|
<label for="pref-quality">{{ t('pref.quality') }}</label>
|
||||||
<select
|
<select
|
||||||
id="pref-quality"
|
id="pref-quality"
|
||||||
name="pref-quality"
|
name="pref-quality"
|
||||||
:value="getStore('quality') || 'auto'"
|
:value="getStore('quality') || 'auto'"
|
||||||
@change="setStore('quality', $event.target.value)">
|
@change="setStore('quality', $event.target.value)">
|
||||||
<option value="auto">{{ useT('pref.auto') }}</option>
|
<option value="auto">{{ t('pref.auto') }}</option>
|
||||||
<option value="best">{{ useT('pref.best') }}</option>
|
<option value="best">{{ t('pref.best') }}</option>
|
||||||
<option value="worst">{{ useT('pref.worst') }}</option>
|
<option value="worst">{{ t('pref.worst') }}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<label for="pref-volume">{{ useT('pref.volume') }}</label>
|
<label for="pref-volume">{{ t('pref.volume') }}</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
name="pref-volume"
|
name="pref-volume"
|
||||||
|
@ -130,7 +131,7 @@ onMounted(() => {
|
||||||
@change="setStore('vol', $event.target.value)" />
|
@change="setStore('vol', $event.target.value)" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>{{ useT('pref.instances.hyp') }}</h2>
|
<h2>{{ t('instances.hyp') }}</h2>
|
||||||
|
|
||||||
<select
|
<select
|
||||||
v-if="hypInstances"
|
v-if="hypInstances"
|
||||||
|
@ -148,8 +149,8 @@ onMounted(() => {
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ useT('pref.instances.name') }}</th>
|
<th>{{ t('instances.name') }}</th>
|
||||||
<th>{{ useT('pref.instances.loc') }}</th>
|
<th>{{ t('instances.loc') }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody v-for="i in hypInstances">
|
<tbody v-for="i in hypInstances">
|
||||||
|
@ -165,7 +166,7 @@ onMounted(() => {
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>{{ useT('pref.instances.piped') }}</h2>
|
<h2>{{ t('instances.piped') }}</h2>
|
||||||
<select
|
<select
|
||||||
v-if="instances"
|
v-if="instances"
|
||||||
:value="getStore('pipedapi') || 'pipedapi.kavin.rocks'"
|
:value="getStore('pipedapi') || 'pipedapi.kavin.rocks'"
|
||||||
|
@ -178,7 +179,7 @@ onMounted(() => {
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<h3>{{ useT('pref.instances.auth') }}</h3>
|
<h3>{{ t('instances.auth') }}</h3>
|
||||||
|
|
||||||
<select
|
<select
|
||||||
v-if="instances"
|
v-if="instances"
|
||||||
|
@ -196,11 +197,11 @@ onMounted(() => {
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ useT('pref.instances.name') }}</th>
|
<th>{{ t('instances.name') }}</th>
|
||||||
<th>{{ useT('pref.instances.loc') }}</th>
|
<th>{{ t('instances.loc') }}</th>
|
||||||
<th>{{ useT('pref.instances.cdn') }}</th>
|
<th>{{ t('instances.cdn') }}</th>
|
||||||
<th>{{ useT('pref.instances.up_to_date') }}</th>
|
<th>{{ t('instances.up_to_date') }}</th>
|
||||||
<th>{{ useT('pref.instances.version') }}</th>
|
<th>{{ t('instances.version') }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody v-for="i in instances">
|
<tbody v-for="i in instances">
|
||||||
|
|
|
@ -8,13 +8,13 @@ import AlbumItem from './AlbumItem.vue';
|
||||||
import { getJsonPiped, getPipedQuery } from '@/scripts/fetch.js';
|
import { getJsonPiped, getPipedQuery } from '@/scripts/fetch.js';
|
||||||
import { useRoute } from '@/scripts/util.js';
|
import { useRoute } from '@/scripts/util.js';
|
||||||
import { useCreatePlaylist } from '@/scripts/db.js';
|
import { useCreatePlaylist } from '@/scripts/db.js';
|
||||||
import { useT } from '@/scripts/i18n.js';
|
|
||||||
|
|
||||||
import { useResults, useArtist } from '@/stores/results.js';
|
import { useResults, useArtist } from '@/stores/results.js';
|
||||||
import { useData } from '@/stores/player.js';
|
import { useData } from '@/stores/player.js';
|
||||||
import { useNav } from '@/stores/misc.js';
|
import { useNav, useI18n } from '@/stores/misc.js';
|
||||||
|
|
||||||
const results = useResults(),
|
const { t } = useI18n(),
|
||||||
|
results = useResults(),
|
||||||
data = useData(),
|
data = useData(),
|
||||||
nav = useNav(),
|
nav = useNav(),
|
||||||
artist = useArtist();
|
artist = useArtist();
|
||||||
|
@ -137,14 +137,14 @@ onUpdated(() => {
|
||||||
getSearch(nav.state.search);
|
getSearch(nav.state.search);
|
||||||
"
|
"
|
||||||
:data-active="f == filter">
|
:data-active="f == filter">
|
||||||
{{ useT('title.' + f.split('_')[1]) }}
|
{{ t('title.' + f.split('_')[1]) }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="results.items.songs && results.items.songs.items[0]"
|
v-if="results.items.songs && results.items.songs.items[0]"
|
||||||
class="search-songs">
|
class="search-songs">
|
||||||
<h2>{{ useT('title.songs') }}</h2>
|
<h2>{{ t('title.songs') }}</h2>
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<template v-for="song in results.items.songs.items">
|
<template v-for="song in results.items.songs.items">
|
||||||
<SongItem
|
<SongItem
|
||||||
|
@ -180,14 +180,14 @@ onUpdated(() => {
|
||||||
"
|
"
|
||||||
class="more"
|
class="more"
|
||||||
:href="'/playlist?list=' + artist.state.playlistId"
|
:href="'/playlist?list=' + artist.state.playlistId"
|
||||||
>{{ useT('info.see_all') }}</a
|
>{{ t('info.see_all') }}</a
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="results.items.albums && results.items.albums.items[0]"
|
v-if="results.items.albums && results.items.albums.items[0]"
|
||||||
class="search-albums">
|
class="search-albums">
|
||||||
<h2>{{ useT('title.albums') }}</h2>
|
<h2>{{ t('title.albums') }}</h2>
|
||||||
<div class="grid-3">
|
<div class="grid-3">
|
||||||
<template v-for="album in results.items.albums.items">
|
<template v-for="album in results.items.albums.items">
|
||||||
<AlbumItem
|
<AlbumItem
|
||||||
|
@ -204,7 +204,7 @@ onUpdated(() => {
|
||||||
<div
|
<div
|
||||||
v-if="results.items.singles && results.items.singles.items[0]"
|
v-if="results.items.singles && results.items.singles.items[0]"
|
||||||
class="search-albums">
|
class="search-albums">
|
||||||
<h2>{{ useT('title.singles') }}</h2>
|
<h2>{{ t('title.singles') }}</h2>
|
||||||
<div class="grid-3">
|
<div class="grid-3">
|
||||||
<template v-for="single in results.items.singles.items">
|
<template v-for="single in results.items.singles.items">
|
||||||
<AlbumItem
|
<AlbumItem
|
||||||
|
@ -225,9 +225,7 @@ onUpdated(() => {
|
||||||
class="search-artists">
|
class="search-artists">
|
||||||
<h2>
|
<h2>
|
||||||
{{
|
{{
|
||||||
results.items.artists
|
results.items.artists ? t('title.artists') : t('title.similar_artists')
|
||||||
? useT('title.artists')
|
|
||||||
: useT('title.similar_artists')
|
|
||||||
}}
|
}}
|
||||||
</h2>
|
</h2>
|
||||||
<div class="grid-3 circle">
|
<div class="grid-3 circle">
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useNav } from '@/stores/misc.js';
|
import { useNav, useI18n } from '@/stores/misc.js';
|
||||||
import { useT } from '@/scripts/i18n.js';
|
|
||||||
|
|
||||||
const show = ref(false),
|
const { t } = useI18n(),
|
||||||
|
show = ref(false),
|
||||||
nav = useNav();
|
nav = useNav();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ const show = ref(false),
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
aria-label="Search Input"
|
aria-label="Search Input"
|
||||||
:placeholder="useT('title.search') + '...'"
|
:placeholder="t('title.search') + '...'"
|
||||||
@change="
|
@change="
|
||||||
nav.state.search = $event.target.value;
|
nav.state.search = $event.target.value;
|
||||||
nav.state.page = 'home';
|
nav.state.page = 'home';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
|
|
||||||
import { useRand } from '../scripts/colors.js';
|
import { useRand } from '@/scripts/colors.js';
|
||||||
|
|
||||||
import { useArtist } from '@/stores/results.js';
|
import { useArtist } from '@/stores/results.js';
|
||||||
import { useData, usePlayer } from '@/stores/player.js';
|
import { useData, usePlayer } from '@/stores/player.js';
|
||||||
|
|
|
@ -6,11 +6,12 @@ import Modal from './Modal.vue';
|
||||||
import { useStore } from '@/scripts/util.js';
|
import { useStore } from '@/scripts/util.js';
|
||||||
import { useListPlaylists, useUpdatePlaylist } from '@/scripts/db.js';
|
import { useListPlaylists, useUpdatePlaylist } from '@/scripts/db.js';
|
||||||
import { getAuthPlaylists, getJsonAuth } from '@/scripts/fetch.js';
|
import { getAuthPlaylists, getJsonAuth } from '@/scripts/fetch.js';
|
||||||
import { useT } from '@/scripts/i18n.js';
|
|
||||||
|
|
||||||
import { useData, usePlayer } from '@/stores/player.js';
|
import { useData, usePlayer } from '@/stores/player.js';
|
||||||
|
import { useI18n } from '@/stores/misc.js';
|
||||||
|
|
||||||
const data = useData(),
|
const { t } = useI18n(),
|
||||||
|
data = useData(),
|
||||||
player = usePlayer(),
|
player = usePlayer(),
|
||||||
store = useStore();
|
store = useStore();
|
||||||
|
|
||||||
|
@ -108,7 +109,7 @@ function Save() {
|
||||||
</template>
|
</template>
|
||||||
<template #buttons>
|
<template #buttons>
|
||||||
<button aria-label="Cancel" @click="showme.pl = false">
|
<button aria-label="Cancel" @click="showme.pl = false">
|
||||||
{{ useT('action.cancel') }}
|
{{ t('action.cancel') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
aria-label="Add Song"
|
aria-label="Add Song"
|
||||||
|
@ -116,7 +117,7 @@ function Save() {
|
||||||
Save();
|
Save();
|
||||||
showme.pl = false;
|
showme.pl = false;
|
||||||
">
|
">
|
||||||
{{ useT('action.add') }}
|
{{ t('action.add') }}
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -41,25 +41,25 @@
|
||||||
"auto": "auto",
|
"auto": "auto",
|
||||||
"best": "best",
|
"best": "best",
|
||||||
"worst": "worst",
|
"worst": "worst",
|
||||||
"volume": "Default Volume",
|
"volume": "Default Volume"
|
||||||
"instances": {
|
|
||||||
"hyp": "Hyperpipe Instance",
|
|
||||||
"piped": "Piped Instance",
|
|
||||||
"auth": "Authentication Instance",
|
|
||||||
"name": "Name",
|
|
||||||
"loc": "Locations",
|
|
||||||
"cdn": "CDN",
|
|
||||||
"up_to_date": "Up to Date",
|
|
||||||
"version": "Version"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"info": {
|
"info": {
|
||||||
"see_all": "See All",
|
"see_all": "See All",
|
||||||
"search": "Start Searching",
|
"search": "Start Searching",
|
||||||
"no_info": "No Information Available",
|
"no_info": "No Information Available"
|
||||||
"lyrics": {
|
},
|
||||||
"load": "Fetching Lyrics",
|
"instances": {
|
||||||
"void": "No Lyrics"
|
"hyp": "Hyperpipe Instance",
|
||||||
}
|
"piped": "Piped Instance",
|
||||||
|
"auth": "Authentication Instance",
|
||||||
|
"name": "Name",
|
||||||
|
"loc": "Locations",
|
||||||
|
"cdn": "CDN",
|
||||||
|
"up_to_date": "Up to Date",
|
||||||
|
"version": "Version"
|
||||||
|
},
|
||||||
|
"lyrics": {
|
||||||
|
"load": "Fetching Lyrics",
|
||||||
|
"void": "No Lyrics"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
src/main.js
14
src/main.js
|
@ -1,26 +1,12 @@
|
||||||
import { createApp } from 'vue';
|
import { createApp } from 'vue';
|
||||||
import { createPinia } from 'pinia';
|
import { createPinia } from 'pinia';
|
||||||
import { createI18n } from 'vue-i18n';
|
|
||||||
|
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
import en from '@/locales/en.json';
|
|
||||||
|
|
||||||
import('bootstrap-icons/font/bootstrap-icons.css');
|
import('bootstrap-icons/font/bootstrap-icons.css');
|
||||||
|
|
||||||
const pinia = createPinia(),
|
const pinia = createPinia(),
|
||||||
i18n = createI18n({
|
|
||||||
globalInjection: true,
|
|
||||||
legacy: false,
|
|
||||||
locale: 'en',
|
|
||||||
fallbackLocale: 'en',
|
|
||||||
messages: {
|
|
||||||
en: en,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
app = createApp(App);
|
app = createApp(App);
|
||||||
|
|
||||||
window.i18n = i18n;
|
|
||||||
|
|
||||||
app.use(i18n);
|
|
||||||
app.use(pinia);
|
app.use(pinia);
|
||||||
app.mount('#app');
|
app.mount('#app');
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
|
|
||||||
export const SUPPORTED_LOCALES = [
|
|
||||||
{
|
|
||||||
code: 'en',
|
|
||||||
name: 'English',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export function useT(path) {
|
|
||||||
const { messages, locale, fallbackLocale } = useI18n(),
|
|
||||||
msgs = messages.value?.[locale.value],
|
|
||||||
fallback = messages.value?.[fallbackLocale.value],
|
|
||||||
keys = path.split('.'),
|
|
||||||
translate = msg => keys.reduce((obj, i) => obj?.[i], msg),
|
|
||||||
translated = translate(msgs) || translate(fallback);
|
|
||||||
|
|
||||||
return translated || path;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useSetupLocale(locale) {
|
|
||||||
import(`@/locales/${locale}.json`)
|
|
||||||
.then(mod => mod.default)
|
|
||||||
.then(mod => {
|
|
||||||
window.i18n.global.messages.value[locale] = mod;
|
|
||||||
});
|
|
||||||
|
|
||||||
window.i18n.global.locale.value = locale;
|
|
||||||
}
|
|
|
@ -1,6 +1,19 @@
|
||||||
import { reactive } from 'vue';
|
import { reactive, ref } from 'vue';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
|
import en from '@/locales/en.json';
|
||||||
|
|
||||||
|
export const SUPPORTED_LOCALES = [
|
||||||
|
{
|
||||||
|
code: 'en',
|
||||||
|
name: 'English',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'fr',
|
||||||
|
name: 'French',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export const useNav = defineStore('nav', () => {
|
export const useNav = defineStore('nav', () => {
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
search: '',
|
search: '',
|
||||||
|
@ -9,3 +22,31 @@ export const useNav = defineStore('nav', () => {
|
||||||
|
|
||||||
return { state };
|
return { state };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const useI18n = defineStore('i18n', () => {
|
||||||
|
const locale = ref('en'),
|
||||||
|
map = ref({
|
||||||
|
en: en,
|
||||||
|
});
|
||||||
|
|
||||||
|
function t(path) {
|
||||||
|
const msgs = map.value[locale.value],
|
||||||
|
fallback = map.value['en'],
|
||||||
|
keys = path.split('.'),
|
||||||
|
translate = msg => keys.reduce((obj, i) => obj?.[i], msg),
|
||||||
|
translated = translate(msgs) || translate(fallback);
|
||||||
|
|
||||||
|
return translated || path;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupLocale(code) {
|
||||||
|
import(`@/locales/${code}.json`)
|
||||||
|
.then(mod => mod.default)
|
||||||
|
.then(mod => {
|
||||||
|
map.value[code] = mod;
|
||||||
|
locale.value = code;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { locale, map, t, setupLocale };
|
||||||
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue