Update all components
This commit is contained in:
parent
592e53486f
commit
ef757e1854
|
@ -13,7 +13,7 @@ const nodeinfo = computed(() => store.state.instance.nodeinfo)
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
title: t('About')
|
||||
title: t('components.About.title')
|
||||
}))
|
||||
|
||||
const podName = computed(() => get(nodeinfo.value, 'metadata.nodeName') ?? 'Funkwhale')
|
||||
|
@ -67,10 +67,10 @@ const headerStyle = computed(() => {
|
|||
<div class="column" />
|
||||
</div>
|
||||
<h2 class="header">
|
||||
A social platform to enjoy and share music
|
||||
{{ $t('components.About.funkwhaleHeader') }}
|
||||
</h2>
|
||||
<p>
|
||||
Funkwhale is a community-driven project that lets you listen and share music and audio within a decentralized, open network.
|
||||
{{ $t('components.About.funkwhaleDescription') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -84,14 +84,14 @@ const headerStyle = computed(() => {
|
|||
class="signup-form content"
|
||||
>
|
||||
<h3 class="header">
|
||||
Sign up
|
||||
{{ $t('components.About.signupHeader') }}
|
||||
</h3>
|
||||
<template v-if="openRegistrations">
|
||||
<p>
|
||||
Sign up now to keep a track of your favorites, create playlists, discover new content and much more!
|
||||
{{ $t('components.About.signupDescription') }}
|
||||
</p>
|
||||
<p v-if="defaultUploadQuota">
|
||||
Users on this pod also get %{ quota } of free storage to upload their own content!
|
||||
{{ $t('components.About.quotaDescription', {quota: defaultUploadQuota}) }}
|
||||
</p>
|
||||
<signup-form
|
||||
button-classes="success"
|
||||
|
@ -100,7 +100,7 @@ const headerStyle = computed(() => {
|
|||
</template>
|
||||
<div v-else>
|
||||
<p>
|
||||
Registrations are closed on this pod. You can signup on another pod using the link below.
|
||||
{{ $t('components.About.registrationsClosedHelp') }}
|
||||
</p>
|
||||
|
||||
<a
|
||||
|
@ -108,7 +108,7 @@ const headerStyle = computed(() => {
|
|||
rel="noopener"
|
||||
href="https://funkwhale.audio/#get-started"
|
||||
>
|
||||
Find another pod
|
||||
{{ $t('components.About.findOtherPod') }}
|
||||
<i class="external alternate icon" />
|
||||
</a>
|
||||
</div>
|
||||
|
@ -118,13 +118,13 @@ const headerStyle = computed(() => {
|
|||
class="signup-form content"
|
||||
>
|
||||
<h3 class="header">
|
||||
Sign up
|
||||
{{ $t('components.About.signupHeader') }}
|
||||
<div class="ui positive message">
|
||||
<div class="header">
|
||||
You're already signed in!
|
||||
{{ $t('components.About.alreadyLoggedIn') }}
|
||||
</div>
|
||||
<p>
|
||||
Hello {{ $store.state.auth.username }}
|
||||
{{ $t('components.About.greetingMessage', {username: $store.state.auth.username}) }}
|
||||
</p>
|
||||
</div>
|
||||
</h3>
|
||||
|
@ -145,7 +145,7 @@ const headerStyle = computed(() => {
|
|||
id="description"
|
||||
class="ui header"
|
||||
>
|
||||
About this pod
|
||||
{{ $t('components.About.aboutPodHeader') }}
|
||||
</h3>
|
||||
<div
|
||||
v-if="shortDescription"
|
||||
|
@ -154,7 +154,7 @@ const headerStyle = computed(() => {
|
|||
{{ shortDescription }}
|
||||
</div>
|
||||
<p v-else>
|
||||
No description available.
|
||||
{{ $t('components.About.noDescription') }}
|
||||
</p>
|
||||
|
||||
<template v-if="stats">
|
||||
|
@ -164,14 +164,14 @@ const headerStyle = computed(() => {
|
|||
<span class="statistics-figure ui text">
|
||||
<span class="ui big text"><strong>{{ stats.users.toLocaleString($store.state.ui.momentLocale) }}</strong></span>
|
||||
<br>
|
||||
{{ $t('active user | active users', stats.users) }}
|
||||
{{ $t('components.About.activeUsers', {users: stats.users}) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="column">
|
||||
<span class="statistics-figure ui text">
|
||||
<span class="ui big text"><strong>{{ stats.hours.toLocaleString($store.state.ui.momentLocale) }}</strong></span>
|
||||
<br>
|
||||
{{ $t('hour of music | hours of music', stats.hours) }}
|
||||
{{ $t('components.About.hoursOfMusic', {hours: stats.hours}) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -182,7 +182,7 @@ const headerStyle = computed(() => {
|
|||
to="/about/pod"
|
||||
class="ui fluid basic secondary button"
|
||||
>
|
||||
Learn More
|
||||
{{ $t('components.About.learnMoreLink') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -201,10 +201,10 @@ const headerStyle = computed(() => {
|
|||
id="description"
|
||||
class="ui header"
|
||||
>
|
||||
Browse public content
|
||||
{{ $t('components.About.publicContentHeader') }}
|
||||
</h3>
|
||||
<p>
|
||||
Listen to public albums and playlists shared on this pod.
|
||||
{{ $t('components.About.publicContentDescription') }}
|
||||
</p>
|
||||
</div>
|
||||
</router-link>
|
||||
|
@ -218,11 +218,11 @@ const headerStyle = computed(() => {
|
|||
id="description"
|
||||
class="ui header"
|
||||
>
|
||||
Find another pod
|
||||
{{ $t('components.About.findOtherPod') }}
|
||||
<i class="external alternate icon" />
|
||||
</h3>
|
||||
<p>
|
||||
Listen to public albums and playlists shared on this pod.
|
||||
{{ $t('components.About.publicContentDescription') }}
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
|
@ -236,11 +236,11 @@ const headerStyle = computed(() => {
|
|||
id="description"
|
||||
class="ui header"
|
||||
>
|
||||
Find an app
|
||||
{{ $t('components.About.findAppHeader') }}
|
||||
<i class="external alternate icon" />
|
||||
</h3>
|
||||
<p>
|
||||
Use Funkwhale on other devices with our apps.
|
||||
{{ $t('components.About.findAppDescription') }}
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
|
@ -250,7 +250,7 @@ const headerStyle = computed(() => {
|
|||
to="/about/pod"
|
||||
class="ui right floated basic secondary button"
|
||||
>
|
||||
About this pod
|
||||
{{ $t('components.About.aboutPodHeader') }}
|
||||
<i class="icon arrow right" />
|
||||
</router-link>
|
||||
</div>
|
||||
|
|
|
@ -21,7 +21,7 @@ fetchData()
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
title: t('About')
|
||||
title: t('components.AboutPod.title')
|
||||
}))
|
||||
|
||||
const podName = computed(() => get(nodeinfo.value, 'metadata.nodeName') || 'Funkwhale')
|
||||
|
@ -99,32 +99,32 @@ const headerStyle = computed(() => {
|
|||
to="/about/pod"
|
||||
class="item"
|
||||
>
|
||||
About this pod
|
||||
{{ $t('components.AboutPod.aboutPod') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
to="/about/pod#rules"
|
||||
class="item"
|
||||
>
|
||||
Rules
|
||||
{{ $t('components.AboutPod.rules') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
to="/about/pod#terms"
|
||||
class="item"
|
||||
>
|
||||
Terms and privacy policy
|
||||
{{ $t('components.AboutPod.termsAndPrivacy') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
to="/about/pod#features"
|
||||
class="item"
|
||||
>
|
||||
Features
|
||||
{{ $t('components.AboutPod.features') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
v-if="stats"
|
||||
to="/about/pod#statistics"
|
||||
class="item"
|
||||
>
|
||||
Statistics
|
||||
{{ $t('components.AboutPod.statistics') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -134,49 +134,49 @@ const headerStyle = computed(() => {
|
|||
id="description about-this-pod"
|
||||
class="ui header"
|
||||
>
|
||||
About this pod
|
||||
{{ $t('components.AboutPod.aboutPod') }}
|
||||
</h2>
|
||||
<sanitized-html
|
||||
v-if="longDescription"
|
||||
:html="longDescription"
|
||||
/>
|
||||
<p v-else>
|
||||
No description available.
|
||||
{{ $t('components.AboutPod.noDescription') }}
|
||||
</p>
|
||||
|
||||
<h3
|
||||
id="rules"
|
||||
class="ui header"
|
||||
>
|
||||
Rules
|
||||
{{ $t('components.AboutPod.rules') }}
|
||||
</h3>
|
||||
<sanitized-html
|
||||
v-if="rules"
|
||||
:html="rules"
|
||||
/>
|
||||
<p v-else>
|
||||
No rules available.
|
||||
{{ $t('components.AboutPod.noRules') }}
|
||||
</p>
|
||||
|
||||
<h3
|
||||
id="terms"
|
||||
class="ui header"
|
||||
>
|
||||
Terms and privacy policy
|
||||
{{ $t('components.AboutPod.termsAndPrivacy') }}
|
||||
</h3>
|
||||
<sanitized-html
|
||||
v-if="terms"
|
||||
:html="terms"
|
||||
/>
|
||||
<p v-else>
|
||||
No terms available.
|
||||
{{ $t('components.AboutPod.noTerms') }}
|
||||
</p>
|
||||
|
||||
<h3
|
||||
id="features"
|
||||
class="header"
|
||||
>
|
||||
Features
|
||||
{{ $t('components.AboutPod.features') }}
|
||||
</h3>
|
||||
<div class="features-container ui two column stackable grid">
|
||||
<div class="column">
|
||||
|
@ -184,7 +184,7 @@ const headerStyle = computed(() => {
|
|||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Funkwhale version
|
||||
{{ $t('components.AboutPod.funkwhaleVersion') }}
|
||||
</td>
|
||||
<td
|
||||
v-if="version"
|
||||
|
@ -199,13 +199,13 @@ const headerStyle = computed(() => {
|
|||
class="right aligned"
|
||||
>
|
||||
<span class="features-status ui text">
|
||||
N/A
|
||||
{{ $t('components.AboutPod.notApplicable') }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Federation
|
||||
{{ $t('components.AboutPod.federation') }}
|
||||
</td>
|
||||
<td
|
||||
v-if="federationEnabled"
|
||||
|
@ -213,7 +213,7 @@ const headerStyle = computed(() => {
|
|||
>
|
||||
<span class="features-status ui text">
|
||||
<i class="check icon" />
|
||||
Enabled
|
||||
{{ $t('components.AboutPod.enabled') }}
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
|
@ -222,13 +222,13 @@ const headerStyle = computed(() => {
|
|||
>
|
||||
<span class="features-status ui text">
|
||||
<i class="x icon" />
|
||||
Disabled
|
||||
{{ $t('components.AboutPod.disabled') }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Allow-list
|
||||
{{ $t('components.AboutPod.allowList') }}
|
||||
</td>
|
||||
<td
|
||||
v-if="allowListEnabled"
|
||||
|
@ -236,7 +236,7 @@ const headerStyle = computed(() => {
|
|||
>
|
||||
<span class="features-status ui text">
|
||||
<i class="check icon" />
|
||||
Enabled
|
||||
{{ $t('components.AboutPod.enabled') }}
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
|
@ -245,7 +245,7 @@ const headerStyle = computed(() => {
|
|||
>
|
||||
<span class="features-status ui text">
|
||||
<i class="x icon" />
|
||||
Disabled
|
||||
{{ $t('components.AboutPod.disabled') }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -257,7 +257,7 @@ const headerStyle = computed(() => {
|
|||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Anonymous access
|
||||
{{ $t('components.AboutPod.anonymousAccess') }}
|
||||
</td>
|
||||
<td
|
||||
v-if="anonymousCanListen"
|
||||
|
@ -265,7 +265,7 @@ const headerStyle = computed(() => {
|
|||
>
|
||||
<span class="features-status ui text">
|
||||
<i class="check icon" />
|
||||
Enabled
|
||||
{{ $t('components.AboutPod.enabled') }}
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
|
@ -274,13 +274,13 @@ const headerStyle = computed(() => {
|
|||
>
|
||||
<span class="features-status ui text">
|
||||
<i class="x icon" />
|
||||
Disabled
|
||||
{{ $t('components.AboutPod.disabled') }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Registrations
|
||||
{{ $t('components.AboutPod.registrations') }}
|
||||
</td>
|
||||
<td
|
||||
v-if="openRegistrations"
|
||||
|
@ -288,7 +288,7 @@ const headerStyle = computed(() => {
|
|||
>
|
||||
<span class="features-status ui text">
|
||||
<i class="check icon" />
|
||||
Open
|
||||
{{ $t('components.AboutPod.open') }}
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
|
@ -297,13 +297,13 @@ const headerStyle = computed(() => {
|
|||
>
|
||||
<span class="features-status ui text">
|
||||
<i class="x icon" />
|
||||
Closed
|
||||
{{ $t('components.AboutPod.closed') }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Upload quota
|
||||
{{ $t('components.AboutPod.uploadQuota') }}
|
||||
</td>
|
||||
<td
|
||||
v-if="defaultUploadQuota"
|
||||
|
@ -318,7 +318,7 @@ const headerStyle = computed(() => {
|
|||
class="right aligned"
|
||||
>
|
||||
<span class="features-status ui text">
|
||||
N/A
|
||||
{{ $t('components.AboutPod.notApplicable') }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -332,7 +332,7 @@ const headerStyle = computed(() => {
|
|||
id="statistics"
|
||||
class="header"
|
||||
>
|
||||
Statistics
|
||||
{{ $t('components.AboutPod.statistics') }}
|
||||
</h3>
|
||||
<div class="statistics-container">
|
||||
<div
|
||||
|
@ -342,7 +342,7 @@ const headerStyle = computed(() => {
|
|||
<span class="statistics-figure ui text">
|
||||
<span class="ui big text"><strong>{{ stats.hours.toLocaleString($store.state.ui.momentLocale) }}</strong></span>
|
||||
<br>
|
||||
{{ $t('hour of music | hours of music', stats.hours) }}
|
||||
{{ $t('components.AboutPod.hoursOfMusic', {hours: stats.hours}) }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
|
@ -352,7 +352,7 @@ const headerStyle = computed(() => {
|
|||
<span class="statistics-figure ui text">
|
||||
<span class="ui big text"><strong>{{ stats.artists.toLocaleString($store.state.ui.momentLocale) }}</strong></span>
|
||||
<br>
|
||||
{{ $t('artist | artists', stats.artists) }}
|
||||
{{ $t('components.AboutPod.artistsCount', {artists: stats.artists}) }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
|
@ -362,7 +362,7 @@ const headerStyle = computed(() => {
|
|||
<span class="statistics-figure ui text">
|
||||
<span class="ui big text"><strong>{{ stats.albums.toLocaleString($store.state.ui.momentLocale) }}</strong></span>
|
||||
<br>
|
||||
{{ $t('album | albums', stats.albums) }}
|
||||
{{ $t('components.AboutPod.albumsCount', {albums: stats.albums}) }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
|
@ -372,7 +372,7 @@ const headerStyle = computed(() => {
|
|||
<span class="statistics-figure ui text">
|
||||
<span class="ui big text"><strong>{{ stats.tracks.toLocaleString($store.state.ui.momentLocale) }}</strong></span>
|
||||
<br>
|
||||
{{ $t('track | tracks', stats.tracks) }}
|
||||
{{ $t('components.AboutPod.tracksCount', {tracks: stats.tracks}) }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
|
@ -382,7 +382,7 @@ const headerStyle = computed(() => {
|
|||
<span class="statistics-figure ui text">
|
||||
<span class="ui big text"><strong>{{ stats.users.toLocaleString($store.state.ui.momentLocale) }}</strong></span>
|
||||
<br>
|
||||
{{ $t('active user | active users', stats.users) }}
|
||||
{{ $t('components.AboutPod.activeUsers', {users: stats.users}) }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
|
@ -392,7 +392,7 @@ const headerStyle = computed(() => {
|
|||
<span class="statistics-figure ui text">
|
||||
<span class="ui big text"><strong>{{ stats.listenings.toLocaleString($store.state.ui.momentLocale) }}</strong></span>
|
||||
<br>
|
||||
{{ $t('listening | listenings', stats.listenings) }}
|
||||
{{ $t('components.AboutPod.listeningsCount', {listenings: stats.listenings}) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -403,13 +403,13 @@ const headerStyle = computed(() => {
|
|||
id="contact"
|
||||
class="ui header"
|
||||
>
|
||||
Contact
|
||||
{{ $t('components.AboutPod.contactHeader') }}
|
||||
</h3>
|
||||
<a
|
||||
v-if="contactEmail"
|
||||
:href="`mailto:${contactEmail}`"
|
||||
>
|
||||
{{ $t('Send us an email: %{ contactEmail }', { contactEmail }) }}
|
||||
{{ $t('components.AboutPod.contactEmail', {contactEmail: contactEmail}) }}
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
@ -420,7 +420,7 @@ const headerStyle = computed(() => {
|
|||
class="ui left floated basic secondary button"
|
||||
>
|
||||
<i class="icon arrow left" />
|
||||
Introduction
|
||||
{{ $t('components.AboutPod.introductionLink') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -14,7 +14,7 @@ import { useRouter } from 'vue-router'
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
title: t('Home')
|
||||
title: t('components.Home.title')
|
||||
}))
|
||||
|
||||
const store = useStore()
|
||||
|
@ -71,7 +71,7 @@ whenever(() => store.state.auth.authenticated, () => {
|
|||
<div class="segment-content">
|
||||
<h1 class="ui center aligned large header">
|
||||
<span>
|
||||
{{ $t('Welcome to %{ podName }!', { podName }) }}
|
||||
{{ $t('components.Home.welcomeMessage', {podName: podName}) }}
|
||||
</span>
|
||||
<div
|
||||
v-if="shortDescription"
|
||||
|
@ -86,7 +86,7 @@ whenever(() => store.state.auth.authenticated, () => {
|
|||
<div class="ui stackable grid">
|
||||
<div class="ten wide column">
|
||||
<h2 class="header">
|
||||
About this Funkwhale pod
|
||||
{{ $t('components.Home.aboutPod') }}
|
||||
</h2>
|
||||
<div
|
||||
id="pod"
|
||||
|
@ -95,7 +95,7 @@ whenever(() => store.state.auth.authenticated, () => {
|
|||
<div class="ui stackable grid">
|
||||
<div class="eight wide column">
|
||||
<p v-if="!longDescription">
|
||||
No description available.
|
||||
{{ $t('components.Home.noDescription') }}
|
||||
</p>
|
||||
<template v-if="longDescription || rules">
|
||||
<sanitized-html
|
||||
|
@ -118,7 +118,7 @@ whenever(() => store.state.auth.authenticated, () => {
|
|||
class="ui link"
|
||||
:to="{name: 'about'}"
|
||||
>
|
||||
Learn more
|
||||
{{ $t('components.Home.learnMore') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -133,7 +133,7 @@ whenever(() => store.state.auth.authenticated, () => {
|
|||
class="ui link"
|
||||
:to="{name: 'about', hash: '#rules'}"
|
||||
>
|
||||
Server rules
|
||||
{{ $t('components.Home.serverRules') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -143,20 +143,20 @@ whenever(() => store.state.auth.authenticated, () => {
|
|||
<div class="eight wide column">
|
||||
<template v-if="stats">
|
||||
<h3 class="sub header">
|
||||
Statistics
|
||||
{{ $t('components.Home.statistics') }}
|
||||
</h3>
|
||||
<p>
|
||||
<i class="user icon" />
|
||||
{{ $t('%{ users } active user | %{ users } active users', stats, stats.users) }}
|
||||
{{ $t('components.Home.activeUsers', {users: stats.users}) }}
|
||||
</p>
|
||||
<p>
|
||||
<i class="music icon" />
|
||||
{{ $t('%{ hours } hour of music | %{ hours } hours of music', stats, stats.hours) }}
|
||||
{{ $t('components.Home.hoursOfMusic', {hours: stats.hours}) }}
|
||||
</p>
|
||||
</template>
|
||||
<template v-if="contactEmail">
|
||||
<h3 class="sub header">
|
||||
Contact
|
||||
{{ $t('components.Home.contactHeader') }}
|
||||
</h3>
|
||||
<i class="at icon" />
|
||||
<a :href="`mailto:${contactEmail}`">{{ contactEmail }}</a>
|
||||
|
@ -179,13 +179,13 @@ whenever(() => store.state.auth.authenticated, () => {
|
|||
<div class="ui stackable grid">
|
||||
<div class="four wide column">
|
||||
<h3 class="header">
|
||||
About Funkwhale
|
||||
{{ $t('components.Home.aboutFunkwhale') }}
|
||||
</h3>
|
||||
<p>
|
||||
This pod runs Funkwhale, a community-driven project that lets you listen and share music and audio within a decentralized, open network.
|
||||
{{ $t('components.Home.funkwhaleDescription') }}
|
||||
</p>
|
||||
<p>
|
||||
Funkwhale is free and developed by a friendly community of volunteers.
|
||||
{{ $t('components.Home.funkwhaleAddendum') }}
|
||||
</p>
|
||||
<a
|
||||
target="_blank"
|
||||
|
@ -193,12 +193,12 @@ whenever(() => store.state.auth.authenticated, () => {
|
|||
href="https://funkwhale.audio"
|
||||
>
|
||||
<i class="external alternate icon" />
|
||||
Visit funkwhale.audio
|
||||
{{ $t('components.Home.websiteLink') }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="four wide column">
|
||||
<h3 class="header">
|
||||
Log In
|
||||
{{ $t('components.Home.loginHeader') }}
|
||||
</h3>
|
||||
<login-form
|
||||
button-classes="success"
|
||||
|
@ -208,14 +208,14 @@ whenever(() => store.state.auth.authenticated, () => {
|
|||
</div>
|
||||
<div class="four wide column">
|
||||
<h3 class="header">
|
||||
Sign up
|
||||
{{ $t('components.Home.signupHeader') }}
|
||||
</h3>
|
||||
<template v-if="openRegistrations">
|
||||
<p>
|
||||
Sign up now to keep track of your favorites, create playlists, discover new content and much more!
|
||||
{{ $t('components.Home.signupDescription') }}
|
||||
</p>
|
||||
<p v-if="defaultUploadQuota">
|
||||
{{ $t('Users on this pod also get %{ quota } of free storage to upload their own content!', { quota: humanSize(defaultUploadQuota * 1000 * 1000) }) }}
|
||||
{{ $t('components.Home.uploadQuota', { quota: humanSize(defaultUploadQuota * 1000 * 1000) }) }}
|
||||
</p>
|
||||
<signup-form
|
||||
button-classes="success"
|
||||
|
@ -224,7 +224,7 @@ whenever(() => store.state.auth.authenticated, () => {
|
|||
</template>
|
||||
<div v-else>
|
||||
<p>
|
||||
Registrations are closed on this pod. You can signup on another pod using the link below.
|
||||
{{ $t('components.Home.registrationsClosed') }}
|
||||
</p>
|
||||
<a
|
||||
target="_blank"
|
||||
|
@ -232,14 +232,14 @@ whenever(() => store.state.auth.authenticated, () => {
|
|||
href="https://funkwhale.audio/#get-started"
|
||||
>
|
||||
<i class="external alternate icon" />
|
||||
Find another pod
|
||||
{{ $t('components.Home.findOtherPod') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="four wide column">
|
||||
<h3 class="header">
|
||||
Useful links
|
||||
{{ $t('components.Home.usefulLinks') }}
|
||||
</h3>
|
||||
<div class="ui relaxed list">
|
||||
<div class="item">
|
||||
|
@ -250,10 +250,10 @@ whenever(() => store.state.auth.authenticated, () => {
|
|||
class="header"
|
||||
to="/library"
|
||||
>
|
||||
Browse public content
|
||||
{{ $t('components.Home.browsePublicContent') }}
|
||||
</router-link>
|
||||
<div class="description">
|
||||
Listen to public albums and playlists shared on this pod
|
||||
{{ $t('components.Home.publicContentDescription') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -266,10 +266,10 @@ whenever(() => store.state.auth.authenticated, () => {
|
|||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
Mobile apps
|
||||
{{ $t('components.Home.mobileApps') }}
|
||||
</a>
|
||||
<div class="description">
|
||||
Use Funkwhale on other devices with our apps
|
||||
{{ $t('components.Home.mobileAppsDescription') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -282,10 +282,10 @@ whenever(() => store.state.auth.authenticated, () => {
|
|||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
User guides
|
||||
{{ $t('components.Home.userGuides') }}
|
||||
</a>
|
||||
<div class="description">
|
||||
Discover everything you need to know about Funkwhale and its features
|
||||
{{ $t('components.Home.userGuidesDescription') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -302,16 +302,16 @@ whenever(() => store.state.auth.authenticated, () => {
|
|||
:limit="10"
|
||||
>
|
||||
<template #title>
|
||||
Recently added albums
|
||||
{{ $t('components.Home.recentlyAddedLabel') }}
|
||||
</template>
|
||||
<router-link to="/library">
|
||||
View more…
|
||||
{{ $t('components.Home.viewMore') }}
|
||||
<div class="ui hidden divider" />
|
||||
</router-link>
|
||||
</album-widget>
|
||||
<div class="ui hidden section divider" />
|
||||
<h3 class="ui header">
|
||||
New channels
|
||||
{{ $t('components.Home.newChannelsLabel') }}
|
||||
</h3>
|
||||
<channels-widget
|
||||
:show-modification-date="true"
|
||||
|
|
|
@ -6,7 +6,7 @@ const path = window.location.href
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
title: t('Page Not Found')
|
||||
title: t('components.PageNotFound.title')
|
||||
}))
|
||||
</script>
|
||||
|
||||
|
@ -20,11 +20,11 @@ const labels = computed(() => ({
|
|||
<h1 class="ui huge header">
|
||||
<i class="warning icon" />
|
||||
<div class="content">
|
||||
Page not found!
|
||||
{{ $t('components.PageNotFound.pageNotFound') }}
|
||||
</div>
|
||||
</h1>
|
||||
<p>
|
||||
Sorry, the page you asked for does not exist:
|
||||
{{ $t('components.PageNotFound.pageNotFoundMessage') }}
|
||||
</p>
|
||||
<a :href="path">{{ path }}</a>
|
||||
<div class="ui hidden divider" />
|
||||
|
@ -32,7 +32,7 @@ const labels = computed(() => ({
|
|||
class="ui icon labeled right button"
|
||||
to="/"
|
||||
>
|
||||
Go to home page
|
||||
{{ $t('components.PageNotFound.homeLink') }}
|
||||
<i class="right arrow icon" />
|
||||
</router-link>
|
||||
</div>
|
||||
|
|
|
@ -55,19 +55,19 @@ const scrollLock = useScrollLock(document.body)
|
|||
const store = useStore()
|
||||
|
||||
const labels = computed(() => ({
|
||||
queue: t('Queue'),
|
||||
populating: t('Fetching radio track'),
|
||||
duration: t('Duration'),
|
||||
addArtistContentFilter: t('Hide content from this artist…'),
|
||||
restart: t('Restart track'),
|
||||
previous: t('Previous track'),
|
||||
next: t('Next track'),
|
||||
pause: t('Pause'),
|
||||
play: t('Play'),
|
||||
fullscreen: t('Fullscreen'),
|
||||
exitFullscreen: t('Exit fullscreen'),
|
||||
showCoverArt: t('Show cover art'),
|
||||
showVisualizer: t('Show visualizer')
|
||||
queue: t('components.Queue.queue'),
|
||||
populating: t('components.Queue.queue.populatingRadio'),
|
||||
duration: t('components.Queue.duration'),
|
||||
addArtistContentFilter: t('components.Queue.addArtistContentFilter'),
|
||||
restart: t('components.Queue.restart'),
|
||||
previous: t('components.Queue.previous'),
|
||||
next: t('components.Queue.next'),
|
||||
pause: t('components.Queue.pause'),
|
||||
play: t('components.Queue.play'),
|
||||
fullscreen: t('components.Queue.enterFullscreen'),
|
||||
exitFullscreen: t('components.Queue.exitFullscreen'),
|
||||
showCoverArt: t('components.Queue.showCoverArt'),
|
||||
showVisualizer: t('components.Queue.showVisualizer')
|
||||
}))
|
||||
|
||||
watchEffect(async () => {
|
||||
|
@ -126,9 +126,9 @@ const queueItems = computed(() => queue.value.map((track, index) => ({
|
|||
...track,
|
||||
key: `${index}-${track.id}`,
|
||||
labels: {
|
||||
remove: t('Remove'),
|
||||
selectTrack: t('Select track'),
|
||||
favorite: t('Favorite track')
|
||||
remove: t('components.Queue.remove'),
|
||||
selectTrack: t('components.Queue.selectTrack'),
|
||||
favorite: t('components.Queue.favorite')
|
||||
},
|
||||
duration: time.durationFormatted(track.uploads[0]?.duration ?? 0) ?? ''
|
||||
}) as QueueItemSource))
|
||||
|
@ -298,14 +298,14 @@ const coverType = useStorage('queue:cover-type', CoverType.COVER_ART)
|
|||
class="ui small warning message"
|
||||
>
|
||||
<h3 class="header">
|
||||
The track cannot be loaded
|
||||
{{ $t('components.Queue.trackLoadFailure') }}
|
||||
</h3>
|
||||
<p v-if="hasNext && isPlaying">
|
||||
The next track will play automatically in a few seconds…
|
||||
{{ $t('components.Queue.automaticPlay') }}
|
||||
<i class="loading spinner icon" />
|
||||
</p>
|
||||
<p>
|
||||
You may have a connectivity issue.
|
||||
{{ $t('components.Queue.connectivityWarning') }}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
|
@ -404,22 +404,18 @@ const coverType = useStorage('queue:cover-type', CoverType.COVER_ART)
|
|||
class="ui right floated basic button"
|
||||
@click="$store.commit('ui/queueFocused', null)"
|
||||
>
|
||||
Close
|
||||
{{ $t('components.Queue.closeButton') }}
|
||||
</button>
|
||||
<button
|
||||
class="ui right floated basic button danger"
|
||||
@click="clear"
|
||||
>
|
||||
Clear
|
||||
{{ $t('components.Queue.clearButton') }}
|
||||
</button>
|
||||
{{ labels.queue }}
|
||||
<div class="sub header">
|
||||
<div>
|
||||
<translate
|
||||
:translate-params="{index: currentIndex + 1, length: queue.length}"
|
||||
>
|
||||
Track %{ index } of %{ length }
|
||||
</translate>
|
||||
{{ $t('components.Queue.queuePosition', {index: currentIndex +1, length: queue.length}) }}
|
||||
<template v-if="!$store.state.radios.running">
|
||||
-
|
||||
<span :title="labels.duration">
|
||||
|
@ -465,16 +461,16 @@ const coverType = useStorage('queue:cover-type', CoverType.COVER_ART)
|
|||
<div class="content">
|
||||
<h3 class="header">
|
||||
<i class="feed icon" />
|
||||
You have a radio playing
|
||||
{{ $t('components.Queue.radioPlaying') }}
|
||||
</h3>
|
||||
<p>
|
||||
New tracks will be appended here automatically.
|
||||
{{ $t('components.Queue.appendTracks') }}
|
||||
</p>
|
||||
<button
|
||||
class="ui basic primary button"
|
||||
@click="$store.dispatch('radios/stop')"
|
||||
>
|
||||
Stop radio
|
||||
{{ $t('components.Queue.stopRadio') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -40,14 +40,14 @@ const errors = ref([] as string[])
|
|||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
title: type.value === 'rss'
|
||||
? t('Subscribe to a podcast RSS feed')
|
||||
: t('Subscribe to a podcast hosted on the Fediverse'),
|
||||
? t('components.RemoteSearchForm.subscribeRss')
|
||||
: t('components.RemoteSearchForm.subscribeFediverse'),
|
||||
fieldLabel: type.value === 'rss'
|
||||
? t('RSS feed location')
|
||||
: t('Fediverse object'),
|
||||
? t('components.RemoteSearchForm.rssLocation')
|
||||
: t('components.RemoteSearchForm.fediverseObject'),
|
||||
fieldPlaceholder: type.value === 'rss'
|
||||
? t('https://website.example.com/rss.xml')
|
||||
: t('@username@example.com')
|
||||
? t('components.RemoteSearchForm.rssPlaceholder')
|
||||
: t('components.RemoteSearchForm.fediversePlaceholder')
|
||||
}))
|
||||
|
||||
const obj = ref()
|
||||
|
@ -117,7 +117,7 @@ const createFetch = async () => {
|
|||
obj.value = response.data
|
||||
|
||||
if (response.data.status === 'errored' || response.data.status === 'skipped') {
|
||||
errors.value.push(t('This object cannot be retrieved'))
|
||||
errors.value.push(t('components.RemoteSearchForm.fetchFailureMessage'))
|
||||
}
|
||||
} catch (error) {
|
||||
errors.value = (error as BackendError).backendErrors
|
||||
|
@ -172,7 +172,7 @@ watch(() => props.initialId, () => {
|
|||
@click.prevent="type = 'rss'"
|
||||
>
|
||||
<i class="feed icon" />
|
||||
RSS
|
||||
{{ $t('components.RemoteSearchForm.rss') }}
|
||||
</button>
|
||||
<div class="or" />
|
||||
<button
|
||||
|
@ -180,7 +180,7 @@ watch(() => props.initialId, () => {
|
|||
@click.prevent="type = 'artists'"
|
||||
>
|
||||
<i class="globe icon" />
|
||||
Fediverse
|
||||
{{ $t('components.RemoteSearchForm.fediverse') }}
|
||||
</button>
|
||||
</div>
|
||||
<div v-else>
|
||||
|
@ -195,7 +195,7 @@ watch(() => props.initialId, () => {
|
|||
class="ui negative message"
|
||||
>
|
||||
<h3 class="header">
|
||||
Error while fetching object
|
||||
{{ $t('components.RemoteSearchForm.objectFetchError') }}
|
||||
</h3>
|
||||
<ul class="list">
|
||||
<li
|
||||
|
@ -211,10 +211,10 @@ watch(() => props.initialId, () => {
|
|||
{{ labels.fieldLabel }}
|
||||
</label>
|
||||
<p v-if="type === 'rss'">
|
||||
Use this form to subscribe to an RSS feed from its URL.
|
||||
{{ $t('components.RemoteSearchForm.rssDescription') }}
|
||||
</p>
|
||||
<p v-else-if="type === 'artists'">
|
||||
Use this form to subscribe to a channel hosted somewhere else on the Fediverse.
|
||||
{{ $t('components.RemoteSearchForm.fediverseDescription') }}
|
||||
</p>
|
||||
<input
|
||||
id="object-id"
|
||||
|
@ -231,7 +231,7 @@ watch(() => props.initialId, () => {
|
|||
:class="['ui', 'primary', {loading: isLoading}, 'button']"
|
||||
:disabled="isLoading || !id || id.length === 0"
|
||||
>
|
||||
Search
|
||||
{{ $t('components.RemoteSearchForm.searchButton') }}
|
||||
</button>
|
||||
</form>
|
||||
<div
|
||||
|
@ -240,7 +240,7 @@ watch(() => props.initialId, () => {
|
|||
class="ui warning message"
|
||||
>
|
||||
<p>
|
||||
This kind of object isn't supported yet
|
||||
{{ $t('components.RemoteSearchForm.unsupportedObject') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -51,7 +51,7 @@ const checkAndSwitch = async (url: string) => {
|
|||
|
||||
show.value = false
|
||||
store.commit('ui/addMessage', {
|
||||
content: t('You are now using the Funkwhale instance at %{ url }', { url: instanceUrl }),
|
||||
content: t('components.SetInstanceModal.currentUrl', { url: instanceUrl }),
|
||||
date: new Date()
|
||||
})
|
||||
|
||||
|
@ -71,7 +71,7 @@ const checkAndSwitch = async (url: string) => {
|
|||
@update:show="isError = false"
|
||||
>
|
||||
<h3 class="header">
|
||||
Choose your instance
|
||||
{{ $t('components.SetInstanceModal.chooseInstance') }}
|
||||
</h3>
|
||||
<div class="scrolling content">
|
||||
<div
|
||||
|
@ -80,14 +80,14 @@ const checkAndSwitch = async (url: string) => {
|
|||
class="ui negative message"
|
||||
>
|
||||
<h4 class="header">
|
||||
It is not possible to connect to the given URL
|
||||
{{ $t('components.SetInstanceModal.connectionFailure') }}
|
||||
</h4>
|
||||
<ul class="list">
|
||||
<li>
|
||||
The server might be down
|
||||
{{ $t('components.SetInstanceModal.serverDown') }}
|
||||
</li>
|
||||
<li>
|
||||
The given address is not a Funkwhale server
|
||||
{{ $t('components.SetInstanceModal.notFunkwhaleServer') }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -97,19 +97,15 @@ const checkAndSwitch = async (url: string) => {
|
|||
>
|
||||
<p
|
||||
v-if="$store.state.instance.instanceUrl"
|
||||
v-translate="{url: $store.state.instance.instanceUrl, hostname: $store.getters['instance/domain'] }"
|
||||
class="description"
|
||||
>
|
||||
You are currently connected to <a
|
||||
href="%{ url }"
|
||||
target="_blank"
|
||||
>%{ hostname } <i class="external icon" /></a>. If you continue, you will be disconnected from your current instance and all your local data will be deleted.
|
||||
{{ $t('components.SetInstanceModal.currentConnection', {url: $store.state.instance.instanceUrl, hostname: $store.getters['instance/domain']}) }}
|
||||
</p>
|
||||
<p v-else>
|
||||
To continue, please select the Funkwhale instance you want to connect to. Enter the address directly, or select one of the suggested choices.
|
||||
{{ $t('components.SetInstanceModal.selectFunkwhalePod') }}
|
||||
</p>
|
||||
<div class="field">
|
||||
<label for="instance-picker">Instance URL</label>
|
||||
<label for="instance-picker">{{ $t('components.SetInstanceModal.instanceUrl') }}</label>
|
||||
<div class="ui action input">
|
||||
<input
|
||||
id="instance-picker"
|
||||
|
@ -121,7 +117,7 @@ const checkAndSwitch = async (url: string) => {
|
|||
type="submit"
|
||||
:class="['ui', 'icon', {loading: isLoading}, 'button']"
|
||||
>
|
||||
Submit
|
||||
{{ $t('components.SetInstanceModal.submitButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -133,7 +129,7 @@ const checkAndSwitch = async (url: string) => {
|
|||
>
|
||||
<div class="field">
|
||||
<h4>
|
||||
Suggested choices
|
||||
{{ $t('components.SetInstanceModal.suggestions') }}
|
||||
</h4>
|
||||
<button
|
||||
v-for="(url, key) in suggestedInstances"
|
||||
|
@ -148,7 +144,7 @@ const checkAndSwitch = async (url: string) => {
|
|||
</div>
|
||||
<div class="actions">
|
||||
<button class="ui basic cancel button">
|
||||
Cancel
|
||||
{{ $t('components.SetInstanceModal.cancelButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</semantic-modal>
|
||||
|
|
|
@ -20,19 +20,19 @@ const showRef = useVModel(props, 'show', emit)
|
|||
const { t } = useI18n()
|
||||
const general = computed(() => [
|
||||
{
|
||||
title: t('General shortcuts'),
|
||||
title: t('components.ShortcutsModal.generalShortcuts'),
|
||||
shortcuts: [
|
||||
{
|
||||
key: 'h',
|
||||
summary: t('Show available keyboard shortcuts')
|
||||
summary: t('components.ShortcutsModal.showShortcuts')
|
||||
},
|
||||
{
|
||||
key: 'shift + f',
|
||||
summary: t('Focus searchbar')
|
||||
summary: t('components.ShortcutsModal.focusSearch')
|
||||
},
|
||||
{
|
||||
key: 'esc',
|
||||
summary: t('Unfocus searchbar')
|
||||
summary: t('components.ShortcutsModal.unfocusSearch')
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -40,67 +40,67 @@ const general = computed(() => [
|
|||
|
||||
const player = computed(() => [
|
||||
{
|
||||
title: t('Audio player shortcuts'),
|
||||
title: t('components.ShortcutsModal.audioShortcuts'),
|
||||
shortcuts: [
|
||||
{
|
||||
key: 'p',
|
||||
summary: t('Pause/play the current track')
|
||||
summary: t('components.ShortcutsModal.playPause')
|
||||
},
|
||||
{
|
||||
key: 'left',
|
||||
summary: t('Seek backwards 5s')
|
||||
summary: t('components.ShortcutsModal.seekBack5')
|
||||
},
|
||||
{
|
||||
key: 'right',
|
||||
summary: t('Seek forwards 5s')
|
||||
summary: t('components.ShortcutsModal.seekForward5')
|
||||
},
|
||||
{
|
||||
key: 'shift + left',
|
||||
summary: t('Seek backwards 30s')
|
||||
summary: t('components.ShortcutsModal.seekBack30')
|
||||
},
|
||||
{
|
||||
key: 'shift + right',
|
||||
summary: t('Seek forwards 30s')
|
||||
summary: t('components.ShortcutsModal.seekForward30')
|
||||
},
|
||||
{
|
||||
key: 'ctrl + shift + left',
|
||||
summary: t('Play previous track')
|
||||
summary: t('components.ShortcutsModal.playPrevious')
|
||||
},
|
||||
{
|
||||
key: 'ctrl + shift + right',
|
||||
summary: t('Play next track')
|
||||
summary: t('components.ShortcutsModal.playNext')
|
||||
},
|
||||
{
|
||||
key: 'shift + up',
|
||||
summary: t('Increase volume')
|
||||
summary: t('components.ShortcutsModal.increaseVolume')
|
||||
},
|
||||
{
|
||||
key: 'shift + down',
|
||||
summary: t('Decrease volume')
|
||||
summary: t('components.ShortcutsModal.decreaseVolume')
|
||||
},
|
||||
{
|
||||
key: 'm',
|
||||
summary: t('Toggle mute')
|
||||
summary: t('components.ShortcutsModal.toggleMute')
|
||||
},
|
||||
{
|
||||
key: 'e',
|
||||
summary: t('Expand queue/player view')
|
||||
summary: t('components.ShortcutsModal.expandQueue')
|
||||
},
|
||||
{
|
||||
key: 'l',
|
||||
summary: t('Toggle queue looping')
|
||||
summary: t('components.ShortcutsModal.toggleLoop')
|
||||
},
|
||||
{
|
||||
key: 's',
|
||||
summary: t('Shuffle queue')
|
||||
summary: t('components.ShortcutsModal.shuffleQueue')
|
||||
},
|
||||
{
|
||||
key: 'q',
|
||||
summary: t('Clear queue')
|
||||
summary: t('components.ShortcutsModal.clearQueue')
|
||||
},
|
||||
{
|
||||
key: 'f',
|
||||
summary: t('Toggle favorite')
|
||||
summary: t('components.ShortcutsModal.toggleFavorite')
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ const player = computed(() => [
|
|||
<template>
|
||||
<semantic-modal v-model:show="showRef">
|
||||
<header class="header">
|
||||
Keyboard shortcuts
|
||||
{{ $t('components.ShortcutsModal.modalHeader') }}
|
||||
</header>
|
||||
<section class="scrolling content">
|
||||
<div class="ui stackable two column grid">
|
||||
|
@ -154,7 +154,7 @@ const player = computed(() => [
|
|||
</section>
|
||||
<footer class="actions">
|
||||
<button class="ui basic cancel button">
|
||||
Close
|
||||
{{ $t('components.ShortcutsModal.closeButton') }}
|
||||
</button>
|
||||
</footer>
|
||||
</semantic-modal>
|
||||
|
|
|
@ -42,15 +42,15 @@ const additionalNotifications = computed(() => store.getters['ui/additionalNotif
|
|||
const logoUrl = computed(() => store.state.auth.authenticated ? 'library.index' : 'index')
|
||||
|
||||
const labels = computed(() => ({
|
||||
mainMenu: t('Main menu'),
|
||||
selectTrack: t('Play this track'),
|
||||
pendingFollows: t('Pending follow requests'),
|
||||
pendingReviewEdits: t('Pending review edits'),
|
||||
pendingReviewReports: t('Pending review reports'),
|
||||
language: t('Language'),
|
||||
theme: t('Theme'),
|
||||
addContent: t('Add content'),
|
||||
administration: t('Administration')
|
||||
mainMenu: t('components.Sidebar.mainMenu'),
|
||||
selectTrack: t('components.Sidebar.selectTrack'),
|
||||
pendingFollows: t('components.Sidebar.pendingFollows'),
|
||||
pendingReviewEdits: t('components.Sidebar.pendingReviewEdits'),
|
||||
pendingReviewReports: t('components.Sidebar.pendingReviewReports'),
|
||||
language: t('components.Sidebar.language'),
|
||||
theme: t('components.Sidebar.theme'),
|
||||
addContent: t('components.Sidebar.addContent'),
|
||||
administration: t('components.Sidebar.administration')
|
||||
}))
|
||||
|
||||
type SidebarMenuTabs = 'explore' | 'myLibrary'
|
||||
|
@ -129,7 +129,7 @@ onMounted(() => {
|
|||
>
|
||||
<i class="logo bordered inverted vibrant big icon">
|
||||
<logo class="logo" />
|
||||
<span class="visually-hidden">Home</span>
|
||||
<span class="visually-hidden">{{ $t('components.Sidebar.home') }}</span>
|
||||
</i>
|
||||
</router-link>
|
||||
<nav class="top ui compact right aligned inverted text menu">
|
||||
|
@ -149,7 +149,7 @@ onMounted(() => {
|
|||
</div>
|
||||
<div class="menu">
|
||||
<h3 class="header">
|
||||
Administration
|
||||
{{ $t('components.Sidebar.administration') }}
|
||||
</h3>
|
||||
<div class="divider" />
|
||||
<router-link
|
||||
|
@ -164,7 +164,7 @@ onMounted(() => {
|
|||
>
|
||||
{{ $store.state.ui.notifications.pendingReviewEdits }}
|
||||
</div>
|
||||
Library
|
||||
{{ $t('components.Sidebar.library') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
v-if="$store.state.auth.availablePermissions['moderation']"
|
||||
|
@ -178,21 +178,21 @@ onMounted(() => {
|
|||
>
|
||||
{{ $store.state.ui.notifications.pendingReviewReports + $store.state.ui.notifications.pendingReviewRequests }}
|
||||
</div>
|
||||
Moderation
|
||||
{{ $t('components.Sidebar.moderation') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
v-if="$store.state.auth.availablePermissions['settings']"
|
||||
class="item"
|
||||
:to="{name: 'manage.users.users.list'}"
|
||||
>
|
||||
Users
|
||||
{{ $t('components.Sidebar.users') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
v-if="$store.state.auth.availablePermissions['settings']"
|
||||
class="item"
|
||||
:to="{path: '/manage/settings'}"
|
||||
>
|
||||
Settings
|
||||
{{ $t('components.Sidebar.settings') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -352,14 +352,14 @@ onMounted(() => {
|
|||
class="ui fluid tiny primary button"
|
||||
:to="{name: 'login'}"
|
||||
>
|
||||
Login
|
||||
{{ $t('components.Sidebar.login') }}
|
||||
</router-link>
|
||||
<div class="ui small hidden divider" />
|
||||
<router-link
|
||||
class="ui fluid tiny button"
|
||||
:to="{path: '/signup'}"
|
||||
>
|
||||
Create an account
|
||||
{{ $t('components.Sidebar.createAccount') }}
|
||||
</router-link>
|
||||
</div>
|
||||
<nav
|
||||
|
@ -371,7 +371,7 @@ onMounted(() => {
|
|||
id="navigation-label"
|
||||
class="visually-hidden"
|
||||
>
|
||||
Main navigation
|
||||
{{ $t('components.Sidebar.mainNavigation') }}
|
||||
</h1>
|
||||
<div class="ui small hidden divider" />
|
||||
<section
|
||||
|
@ -391,7 +391,7 @@ onMounted(() => {
|
|||
@click="expanded = 'explore'"
|
||||
@focus="expanded = 'explore'"
|
||||
>
|
||||
Explore
|
||||
{{ $t('components.Sidebar.explore') }}
|
||||
<i
|
||||
v-if="expanded !== 'explore'"
|
||||
class="angle right icon"
|
||||
|
@ -402,44 +402,51 @@ onMounted(() => {
|
|||
class="item"
|
||||
:to="{name: 'search'}"
|
||||
>
|
||||
<i class="search icon" /> Search
|
||||
<i class="search icon" />
|
||||
{{ $t('components.Sidebar.search') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
class="item"
|
||||
:to="{name: 'library.index'}"
|
||||
active-class="_active"
|
||||
>
|
||||
<i class="music icon" /> Browse
|
||||
<i class="music icon" />
|
||||
{{ $t('components.Sidebar.browse') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
class="item"
|
||||
:to="{name: 'library.podcasts.browse'}"
|
||||
>
|
||||
<i class="podcast icon" /> Podcasts
|
||||
<i class="podcast icon" />
|
||||
{{ $t('components.Sidebar.podcasts') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
class="item"
|
||||
:to="{name: 'library.albums.browse'}"
|
||||
>
|
||||
<i class="compact disc icon" /> Albums
|
||||
<i class="compact disc icon" />
|
||||
{{ $t('components.Sidebar.albums') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
class="item"
|
||||
:to="{name: 'library.artists.browse'}"
|
||||
>
|
||||
<i class="user icon" /> Artists
|
||||
<i class="user icon" />
|
||||
{{ $t('components.Sidebar.artists') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
class="item"
|
||||
:to="{name: 'library.playlists.browse'}"
|
||||
>
|
||||
<i class="list icon" /> Playlists
|
||||
<i class="list icon" />
|
||||
{{ $t('components.Sidebar.playlists') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
class="item"
|
||||
:to="{name: 'library.radios.browse'}"
|
||||
>
|
||||
<i class="feed icon" /> Radios
|
||||
<i class="feed icon" />
|
||||
{{ $t('components.Sidebar.radios') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -454,7 +461,7 @@ onMounted(() => {
|
|||
@click="expanded = 'myLibrary'"
|
||||
@focus="expanded = 'myLibrary'"
|
||||
>
|
||||
My Library
|
||||
{{ $t('components.Sidebar.myLibrary') }}
|
||||
<i
|
||||
v-if="expanded !== 'myLibrary'"
|
||||
class="angle right icon"
|
||||
|
@ -465,37 +472,43 @@ onMounted(() => {
|
|||
class="item"
|
||||
:to="{name: 'library.me'}"
|
||||
>
|
||||
<i class="music icon" /> Browse
|
||||
<i class="music icon" />
|
||||
{{ $t('components.Sidebar.browse') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
class="item"
|
||||
:to="{name: 'library.albums.me'}"
|
||||
>
|
||||
<i class="compact disc icon" /> Albums
|
||||
<i class="compact disc icon" />
|
||||
{{ $t('components.Sidebar.albums') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
class="item"
|
||||
:to="{name: 'library.artists.me'}"
|
||||
>
|
||||
<i class="user icon" /> Artists
|
||||
<i class="user icon" />
|
||||
{{ $t('components.Sidebar.artists') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
class="item"
|
||||
:to="{name: 'library.playlists.me'}"
|
||||
>
|
||||
<i class="list icon" /> Playlists
|
||||
<i class="list icon" />
|
||||
{{ $t('components.Sidebar.playlists') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
class="item"
|
||||
:to="{name: 'library.radios.me'}"
|
||||
>
|
||||
<i class="feed icon" /> Radios
|
||||
<i class="feed icon" />
|
||||
{{ $t('components.Sidebar.radios') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
class="item"
|
||||
:to="{name: 'favorites'}"
|
||||
>
|
||||
<i class="heart icon" /> Favorites
|
||||
<i class="heart icon" />
|
||||
{{ $t('components.Sidebar.favorites') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -504,11 +517,11 @@ onMounted(() => {
|
|||
class="header item"
|
||||
:to="{name: 'subscriptions'}"
|
||||
>
|
||||
Channels
|
||||
{{ $t('components.Sidebar.channels') }}
|
||||
</router-link>
|
||||
<div class="item">
|
||||
<h3 class="header">
|
||||
More
|
||||
{{ $t('components.Sidebar.more') }}
|
||||
</h3>
|
||||
<div class="menu">
|
||||
<router-link
|
||||
|
@ -516,7 +529,8 @@ onMounted(() => {
|
|||
to="/about"
|
||||
active-class="router-link-exact-active active"
|
||||
>
|
||||
<i class="info icon" /> About this pod
|
||||
<i class="info icon" />
|
||||
{{ $t('components.Sidebar.aboutPod') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -529,7 +543,7 @@ onMounted(() => {
|
|||
href=""
|
||||
class="link item"
|
||||
@click.prevent="emit('show:set-instance-modal')"
|
||||
>Switch instance</a>
|
||||
>{{ $t('components.Sidebar.switchInstance') }}</a>
|
||||
</div>
|
||||
</nav>
|
||||
</section>
|
||||
|
|
|
@ -75,7 +75,7 @@ const move = (idx: number, increment: number) => {
|
|||
:class="[{active: isPreviewing}, 'item']"
|
||||
@click.stop.prevent="isPreviewing = true"
|
||||
>
|
||||
{{ $t('components.admin.SignupFormBuilder.previewForm') }}
|
||||
{{ $t('components.admin.SignupFormBuilder.previewForm') }}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
|
@ -126,7 +126,7 @@ const move = (idx: number, increment: number) => {
|
|||
<th>
|
||||
{{ $t('components.admin.SignupFormBuilder.requiredTableHeader') }}
|
||||
</th>
|
||||
<th><span class="visually-hidden">Actions</span></th>
|
||||
<th><span class="visually-hidden">{{ $t('components.admin.SignupFormBuilder.actionsTableHeader') }}</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
@ -68,12 +68,12 @@ const updatedAgo = computed(() => moment(props.object.artist?.modification_date)
|
|||
v-if="object.artist?.content_category === 'podcast'"
|
||||
class="meta ellipsis"
|
||||
>
|
||||
{{ $t('components.audio.ChannelCard.episodeCount', object.artist.tracks_count) }}
|
||||
{{ $t('components.audio.ChannelCard.episodeCount', {episode_count: object.artist.tracks_count}) }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
{{ $t('components.audio.ChannelCard.trackCount', object.artist?.tracks_count) }}
|
||||
{{ $t('components.audio.ChannelCard.trackCount', {tracks_count: object.artist?.tracks_count}) }}
|
||||
</span>
|
||||
<tags-list
|
||||
label-classes="tiny"
|
||||
|
@ -86,13 +86,11 @@ const updatedAgo = computed(() => moment(props.object.artist?.modification_date)
|
|||
</div>
|
||||
<div class="extra content">
|
||||
<time
|
||||
v-translate="{ updatedAgo }"
|
||||
:translate-params="{ updatedAgo }"
|
||||
class="meta ellipsis"
|
||||
:datetime="object.artist?.modification_date"
|
||||
:title="updatedTitle"
|
||||
>
|
||||
{{ $t('{ updatedAgo }') }}
|
||||
{{ updatedAgo }}
|
||||
</time>
|
||||
<play-button
|
||||
class="right floated basic icon"
|
||||
|
|
|
@ -300,7 +300,7 @@ const hideArtist = () => {
|
|||
>
|
||||
<i class="stream icon" />
|
||||
<span>
|
||||
{{ $t('components.audio.Player.queuePosition', { index: currentIndex + 1 }, { length: queue.length }) }}
|
||||
{{ $t('components.audio.Player.queuePosition', { index: currentIndex + 1, length: queue.length }) }}
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
|
@ -308,7 +308,9 @@ const hideArtist = () => {
|
|||
@click.stop="switchTab"
|
||||
>
|
||||
<i class="stream icon" />
|
||||
{{ $t('components.audio.Player.queuePosition', { index: currentIndex + 1 }, { length: queue.length }) }}
|
||||
<span>
|
||||
{{ $t('components.audio.Player.queuePosition', { index: currentIndex + 1, length: queue.length }) }}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
|
|
|
@ -159,7 +159,7 @@ whenever(() => props.clientId, fetchApplication, { immediate: true })
|
|||
@submit.prevent="submit"
|
||||
>
|
||||
<h3>
|
||||
{{ $t('components.auth.Authorize.appAccessHeader', app: application.name) }}
|
||||
{{ $t('components.auth.Authorize.appAccessHeader', {app_name: application.name}) }}
|
||||
</h3>
|
||||
|
||||
<h4
|
||||
|
@ -219,7 +219,7 @@ whenever(() => props.clientId, fetchApplication, { immediate: true })
|
|||
<p
|
||||
v-else
|
||||
>
|
||||
{{ $t('components.auth.Authorize.redirectHelp', url: redirectUri) }}
|
||||
{{ $t('components.auth.Authorize.redirectHelp', {url: redirectUri}) }}
|
||||
</p>
|
||||
</form>
|
||||
<div v-else-if="code">
|
||||
|
|
|
@ -69,7 +69,7 @@ const submitAndScan = async () => {
|
|||
target="_blank"
|
||||
>
|
||||
<i class="external icon" />
|
||||
{{ $t('components.auth.Plugin.documentationLink') }}
|
||||
{{ $t('components.auth.Plugin.documentationLink') }}
|
||||
</a>
|
||||
</template>
|
||||
<div class="ui clearing hidden divider" />
|
||||
|
|
|
@ -573,7 +573,7 @@ fetchOwnedApps()
|
|||
{{ $t('components.auth.Settings.permissionDeleteButton') }}
|
||||
<template #modal-header>
|
||||
<p>
|
||||
{{ $t('components.auth.Settings.revokePermissionModalMessage', app: app.name) }}
|
||||
{{ $t('components.auth.Settings.revokePermissionModalMessage', {app: app.name}) }}
|
||||
</p>
|
||||
</template>
|
||||
<template #modal-content>
|
||||
|
@ -665,9 +665,8 @@ fetchOwnedApps()
|
|||
>
|
||||
{{ $t('components.auth.Settings.personalAppDeleteLink') }}
|
||||
<template #modal-header>
|
||||
<p>
|
||||
{{ $t('components.auth.Settings.deletePersonalAppModalMessage', app: app.name) }}
|
||||
</p>
|
||||
<p />
|
||||
{{ $t('components.auth.Settings.deletePersonalAppModalMessage', {app: app.name}) }}
|
||||
</template>
|
||||
<template #modal-content>
|
||||
<p>
|
||||
|
@ -688,7 +687,7 @@ fetchOwnedApps()
|
|||
<template #title>
|
||||
{{ $t('components.auth.Settings.emptyPersonalAppMessage') }}
|
||||
</template>
|
||||
{{ $t('components.auth.Settings.emptyPersonalAppHelp') }}
|
||||
{{ $t('components.auth.Settings.emptyPersonalAppHelp') }}
|
||||
</empty-state>
|
||||
</section>
|
||||
|
||||
|
@ -758,7 +757,7 @@ fetchOwnedApps()
|
|||
>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="current-password-field-email">{{ $t('components.auth.Settings.currentPasswordLabel')} }}</label>
|
||||
<label for="current-password-field-email">{{ $t('components.auth.Settings.currentPasswordLabel') }}</label>
|
||||
<password-input
|
||||
v-model="emailPassword"
|
||||
field-id="current-password-field-email"
|
||||
|
|
|
@ -195,7 +195,7 @@ fetchToken()
|
|||
</template>
|
||||
<template #modal-confirm>
|
||||
<div>
|
||||
{{ $t('components.auth.SubsonicTokenForm.disableSubsonicAccessConfirm')}}
|
||||
{{ $t('components.auth.SubsonicTokenForm.disableSubsonicAccessConfirm') }}
|
||||
</div>
|
||||
</template>
|
||||
</dangerous-button>
|
||||
|
|
|
@ -60,7 +60,7 @@ watch(() => props.channel, fetchData, { immediate: true })
|
|||
class="ui search normal dropdown"
|
||||
>
|
||||
<option value="">
|
||||
None
|
||||
{{ $t('components.channels.AlbumSelect.noneLabel') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="album in albums"
|
||||
|
|
|
@ -185,7 +185,7 @@ const launchAction = async () => {
|
|||
>
|
||||
<div class="ui inline fields">
|
||||
<div class="field">
|
||||
<label for="actions-select">Actions</label>
|
||||
<label for="actions-select">{{ $t('components.common.ActionTable.actionsLabel') }}</label>
|
||||
<select
|
||||
id="actions-select"
|
||||
v-model="currentActionName"
|
||||
|
@ -214,7 +214,7 @@ const launchAction = async () => {
|
|||
<span
|
||||
key="1"
|
||||
>
|
||||
{{ $t('components.common.ActionTable.performActionConfirmation', {action: currentActionName}, {count: affectedObjectsCount} ) }}
|
||||
{{ $t('components.common.ActionTable.performActionConfirmation', {action: currentActionName, count: affectedObjectsCount} ) }}
|
||||
</span>
|
||||
</p>
|
||||
</template>
|
||||
|
@ -250,12 +250,12 @@ const launchAction = async () => {
|
|||
<span
|
||||
v-if="selectAll"
|
||||
>
|
||||
{{ $t('components.common.ActionTable.allElementsSelectedMessage', {count: objectData.count}) }}
|
||||
{{ $t('components.common.ActionTable.allElementsSelectedMessage', {count: objectsData.count}) }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
{{ $t('components.common.ActionTable.elementsSelectedMessage', {count: checked.length }, {total: objectsData.count}) }}
|
||||
{{ $t('components.common.ActionTable.elementsSelectedMessage', {count: checked.length, total: objectsData.count}) }}
|
||||
</span>
|
||||
<template v-if="currentAction?.allowAll && checkable.length > 0 && checkable.length === checked.length">
|
||||
<a
|
||||
|
@ -303,9 +303,8 @@ const launchAction = async () => {
|
|||
class="ui positive message"
|
||||
>
|
||||
<p>
|
||||
<span
|
||||
>
|
||||
{{ $t('components.common.ActionTable.actionSuccessMessage', {action: result.action}, {count: result.updated}) }}
|
||||
<span>
|
||||
{{ $t('components.common.ActionTable.actionSuccessMessage', {action: result.action, count: result.updated}) }}
|
||||
</span>
|
||||
</p>
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ const duration = computed(() => {
|
|||
<span>
|
||||
<span
|
||||
v-if="duration.hours > 0"
|
||||
>{{ $t('components.common.Duration.hoursFormat', {hours: duration.hours}, {minutes: duration.minutes}) }}</span>
|
||||
>{{ $t('components.common.Duration.hoursFormat', {hours: duration.hours, minutes: duration.minutes}) }}</span>
|
||||
<span
|
||||
v-else
|
||||
>{{ $t('components.common.Duration.minutesFormat', {minutes: duration.minutes}) }}</span>
|
||||
|
|
|
@ -91,19 +91,19 @@ const submit = async () => {
|
|||
href=""
|
||||
@click.stop.prevent="showMore = true"
|
||||
>
|
||||
Show more
|
||||
{{ $t('components.common.RenderedDescription.showMore') }}
|
||||
</a>
|
||||
<a
|
||||
v-else
|
||||
href=""
|
||||
@click.stop.prevent="showMore = false"
|
||||
>
|
||||
Show less
|
||||
{{ $t('components.common.RenderedDescription.showLess') }}
|
||||
</a>
|
||||
</template>
|
||||
</template>
|
||||
<p v-else-if="!isUpdating">
|
||||
No description available
|
||||
{{ $t('components.common.RenderedDescription.noDescription') }}
|
||||
</p>
|
||||
<template v-if="!isUpdating && canUpdate && updateUrl">
|
||||
<div class="ui hidden divider" />
|
||||
|
@ -112,7 +112,7 @@ const submit = async () => {
|
|||
@click="isUpdating = true"
|
||||
>
|
||||
<i class="pencil icon" />
|
||||
Edit
|
||||
{{ $t('components.common.RenderedDescription.editButton') }}
|
||||
</span>
|
||||
</template>
|
||||
<form
|
||||
|
@ -126,7 +126,7 @@ const submit = async () => {
|
|||
class="ui negative message"
|
||||
>
|
||||
<h4 class="header">
|
||||
Error while updating description
|
||||
{{ $t('components.common.RenderedDescription.updateFailureHeader') }}
|
||||
</h4>
|
||||
<ul class="list">
|
||||
<li
|
||||
|
@ -145,14 +145,14 @@ const submit = async () => {
|
|||
class="left floated"
|
||||
@click.prevent="isUpdating = false"
|
||||
>
|
||||
Cancel
|
||||
{{ $t('components.common.RenderedDescription.cancelButton') }}
|
||||
</a>
|
||||
<button
|
||||
:class="['ui', {'loading': isLoading}, 'right', 'floated', 'button']"
|
||||
type="submit"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
Update description
|
||||
{{ $t('components.common.RenderedDescription.updateButton') }}
|
||||
</button>
|
||||
<div class="ui clearing hidden divider" />
|
||||
</form>
|
||||
|
|
|
@ -17,21 +17,21 @@ const themes = useThemeList()
|
|||
const { theme } = useTheme()
|
||||
|
||||
const labels = computed(() => ({
|
||||
profile: t('Profile'),
|
||||
settings: t('Settings'),
|
||||
logout: t('Log out'),
|
||||
about: t('About'),
|
||||
shortcuts: t('Keyboard shortcuts'),
|
||||
support: t('Help'),
|
||||
forum: t('Forum'),
|
||||
docs: t('Documentation'),
|
||||
language: t('Change language'),
|
||||
theme: t('Change theme'),
|
||||
chat: t('Chat room'),
|
||||
git: t('Issue tracker'),
|
||||
login: t('Log in'),
|
||||
signup: t('Sign up'),
|
||||
notifications: t('Notifications')
|
||||
profile: t('components.common.UserMenu.profileLabel'),
|
||||
settings: t('components.common.UserMenu.settingsLabel'),
|
||||
logout: t('components.common.UserMenu.logoutLabel'),
|
||||
about: t('components.common.UserMenu.aboutLabel'),
|
||||
shortcuts: t('components.common.UserMenu.shortcutsLabel'),
|
||||
support: t('components.common.UserMenu.supportLabel'),
|
||||
forum: t('components.common.UserMenu.forumLabel'),
|
||||
docs: t('components.common.UserMenu.docsLabel'),
|
||||
language: t('components.common.UserMenu.languageLabel'),
|
||||
theme: t('components.common.UserMenu.themeLabel'),
|
||||
chat: t('components.common.UserMenu.chatLabel'),
|
||||
git: t('components.common.UserMenu.gitLabel'),
|
||||
login: t('components.common.UserMenu.loginLabel'),
|
||||
signup: t('components.common.UserMenu.signupLabel'),
|
||||
notifications: t('components.common.UserMenu.notificationsLabel')
|
||||
}))
|
||||
</script>
|
||||
|
||||
|
|
|
@ -26,24 +26,24 @@ const themes = useThemeList()
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
header: t('Options'),
|
||||
profile: t('Profile'),
|
||||
settings: t('Settings'),
|
||||
logout: t('Log out'),
|
||||
about: t('About'),
|
||||
shortcuts: t('Keyboard shortcuts'),
|
||||
support: t('Help'),
|
||||
forum: t('Forum'),
|
||||
docs: t('Documentation'),
|
||||
help: t('Help'),
|
||||
language: t('Language'),
|
||||
theme: t('Theme'),
|
||||
chat: t('Chat room'),
|
||||
git: t('Issue tracker'),
|
||||
login: t('Log in'),
|
||||
signup: t('Sign up'),
|
||||
notifications: t('Notifications'),
|
||||
useOtherInstance: t('Use another instance')
|
||||
header: t('components.common.UserModal.optionsLabel'),
|
||||
profile: t('components.common.UserModal.profileLabel'),
|
||||
settings: t('components.common.UserModal.settingsLabel'),
|
||||
logout: t('components.common.UserModal.logoutLabel'),
|
||||
about: t('components.common.UserModal.aboutLabel'),
|
||||
shortcuts: t('components.common.UserModal.shortcutsLabel'),
|
||||
support: t('components.common.UserModal.supportLabel'),
|
||||
forum: t('components.common.UserModal.forumLabel'),
|
||||
docs: t('components.common.UserModal.docsLabel'),
|
||||
help: t('components.common.UserModal.supportLabel'),
|
||||
language: t('components.common.UserModal.languageLabel'),
|
||||
theme: t('components.common.UserModal.themeLabel'),
|
||||
chat: t('components.common.UserModal.chatLabel'),
|
||||
git: t('components.common.UserModal.gitLabel'),
|
||||
login: t('components.common.UserModal.loginLabel'),
|
||||
signup: t('components.common.UserModal.signupLabel'),
|
||||
notifications: t('components.common.UserModal.notificationsLabel'),
|
||||
useOtherInstance: t('components.common.UserModal.useOtherInstanceLabel')
|
||||
}))
|
||||
</script>
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ onMounted(() => $('.ui.dropdown').dropdown())
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
title: t('Your Favorites')
|
||||
title: t('components.favorites.List.title')
|
||||
}))
|
||||
|
||||
const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value].sort((a, b) => a - b)))
|
||||
|
@ -112,7 +112,7 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
<section class="ui vertical center aligned stripe segment">
|
||||
<div :class="['ui', { 'active': isLoading }, 'inverted', 'dimmer']">
|
||||
<div class="ui text loader">
|
||||
Loading your favorites…
|
||||
{{ $t('components.favorites.List.loadingMessage') }}
|
||||
</div>
|
||||
</div>
|
||||
<h2
|
||||
|
@ -120,13 +120,7 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
class="ui center aligned icon header"
|
||||
>
|
||||
<i class="circular inverted heart pink icon" />
|
||||
<translate
|
||||
translate-plural="%{ count } favorites"
|
||||
:translate-n="$store.state.favorites.count"
|
||||
:translate-params="{ count }"
|
||||
>
|
||||
%{ count } favorite
|
||||
</translate>
|
||||
{{ $t('components.favorites.List.favoritesCount', {count: $store.state.favorites.count}) }}
|
||||
</h2>
|
||||
<radio-button
|
||||
v-if="$store.state.favorites.count > 0"
|
||||
|
@ -141,7 +135,7 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
<div class="fields">
|
||||
<div class="field">
|
||||
<label for="favorites-ordering">
|
||||
Ordering
|
||||
{{ $t('components.favorites.List.favoritesOrderingLabel') }}
|
||||
</label>
|
||||
<select
|
||||
id="favorites-ordering"
|
||||
|
@ -159,7 +153,7 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
</div>
|
||||
<div class="field">
|
||||
<label for="favorites-ordering-direction">
|
||||
Order
|
||||
{{ $t('components.favorites.List.favoritesOrderingDirectionLabel') }}
|
||||
</label>
|
||||
<select
|
||||
id="favorites-ordering-direction"
|
||||
|
@ -167,16 +161,16 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
class="ui dropdown"
|
||||
>
|
||||
<option value="+">
|
||||
Ascending
|
||||
{{ $t('components.favorites.List.orderingDirectionAscending') }}
|
||||
</option>
|
||||
<option value="-">
|
||||
Descending
|
||||
{{ $t('components.favorites.List.orderingDirectionDescending') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="favorites-results">
|
||||
Results per page
|
||||
{{ $t('components.favorites.List.favoritesResultsPerPageLabel') }}
|
||||
</label>
|
||||
<select
|
||||
id="favorites-results"
|
||||
|
@ -215,14 +209,14 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
>
|
||||
<div class="ui icon header">
|
||||
<i class="broken heart icon" />
|
||||
No tracks have been added to your favorites yet
|
||||
{{ $t('components.favorites.List.emptyState') }}
|
||||
</div>
|
||||
<router-link
|
||||
:to="'/library'"
|
||||
class="ui success labeled icon button"
|
||||
>
|
||||
<i class="headphones icon" />
|
||||
Browse the library
|
||||
{{ $t('components.favorites.List.libraryLink') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</main>
|
||||
|
|
|
@ -23,8 +23,8 @@ const store = useStore()
|
|||
|
||||
const isFavorite = computed(() => store.getters['favorites/isFavorite'](props.track.id))
|
||||
const title = computed(() => isFavorite.value
|
||||
? t('Remove from favorites')
|
||||
: t('Add to favorites')
|
||||
? t('components.favorites.TrackFavoriteIcon.removeFromFavorites')
|
||||
: t('components.favorites.TrackFavoriteIcon.addToFavorites')
|
||||
)
|
||||
</script>
|
||||
|
||||
|
@ -35,16 +35,16 @@ const title = computed(() => isFavorite.value
|
|||
@click.stop="$store.dispatch('favorites/toggle', track.id)"
|
||||
>
|
||||
<i class="heart icon" />
|
||||
<translate
|
||||
<span
|
||||
v-if="isFavorite"
|
||||
>
|
||||
In favorites
|
||||
</translate>
|
||||
<translate
|
||||
{{ $t('components.favorites.TrackFavoriteIcon.isFavorited') }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
Add to favorites
|
||||
</translate>
|
||||
{{ $t('components.favorites.TrackFavoriteIcon.addToFavorites') }}
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
v-else
|
||||
|
|
|
@ -80,7 +80,7 @@ const { start: startPolling } = useTimeoutFn(poll, 1000, { immediate: false })
|
|||
class="small"
|
||||
>
|
||||
<h3 class="header">
|
||||
Refreshing object from remote server…
|
||||
{{ $t('components.federation.FetchButton.remoteRefreshHeader') }}
|
||||
</h3>
|
||||
<div class="scrolling content">
|
||||
<template v-if="data && data.status != 'pending'">
|
||||
|
@ -89,10 +89,10 @@ const { start: startPolling } = useTimeoutFn(poll, 1000, { immediate: false })
|
|||
class="ui message"
|
||||
>
|
||||
<h4 class="header">
|
||||
Refresh was skipped
|
||||
{{ $t('components.federation.FetchButton.refreshSkippedHeader') }}
|
||||
</h4>
|
||||
<p>
|
||||
The remote server answered, but returned data was unsupported by Funkwhale.
|
||||
{{ $t('components.federation.FetchButton.unsupportedDataMessage') }}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
|
@ -100,10 +100,10 @@ const { start: startPolling } = useTimeoutFn(poll, 1000, { immediate: false })
|
|||
class="ui success message"
|
||||
>
|
||||
<h4 class="header">
|
||||
Refresh successful
|
||||
{{ $t('components.federation.FetchButton.refreshSuccessHeader') }}
|
||||
</h4>
|
||||
<p>
|
||||
Data was refreshed successfully from remote server.
|
||||
{{ $t('components.federation.FetchButton.refreshSuccessMessage') }}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
|
@ -111,16 +111,16 @@ const { start: startPolling } = useTimeoutFn(poll, 1000, { immediate: false })
|
|||
class="ui error message"
|
||||
>
|
||||
<h4 class="header">
|
||||
Refresh error
|
||||
{{ $t('components.federation.FetchButton.refreshFailureHeader') }}
|
||||
</h4>
|
||||
<p>
|
||||
An error occurred while trying to refresh data:
|
||||
{{ $t('components.federation.FetchButton.refreshFailureMessage') }}
|
||||
</p>
|
||||
<table class="ui very basic collapsing celled table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Error type
|
||||
{{ $t('components.federation.FetchButton.errorTypeTableHeader') }}
|
||||
</td>
|
||||
<td>
|
||||
{{ data.detail.error_code }}
|
||||
|
@ -128,50 +128,49 @@ const { start: startPolling } = useTimeoutFn(poll, 1000, { immediate: false })
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Error detail
|
||||
{{ $t('components.federation.FetchButton.errorDetailTableRow') }}
|
||||
</td>
|
||||
<td>
|
||||
<translate
|
||||
<span
|
||||
v-if="data.detail.error_code === 'http' && data.detail.status_code"
|
||||
:translate-params="{status: data.detail.status_code}"
|
||||
>
|
||||
The remote server answered with HTTP %{ status }
|
||||
</translate>
|
||||
<translate
|
||||
{{ $t('components.federation.FetchButton.httpStatusMessage', {status: data.detail.status_code}) }}
|
||||
</span>
|
||||
<span
|
||||
v-else-if="['http', 'request'].indexOf(data.detail.error_code) > -1"
|
||||
>
|
||||
An HTTP error occurred while contacting the remote server
|
||||
</translate>
|
||||
<translate
|
||||
{{ $t('components.federation.FetchButton.httpErrorMessage') }}
|
||||
</span>
|
||||
<span
|
||||
v-else-if="data.detail.error_code === 'timeout'"
|
||||
>
|
||||
The remote server didn't respond quickly enough
|
||||
</translate>
|
||||
<translate
|
||||
{{ $t('components.federation.FetchButton.timeoutErrorMessage') }}
|
||||
</span>
|
||||
<span
|
||||
v-else-if="data.detail.error_code === 'connection'"
|
||||
>
|
||||
Impossible to connect to the remote server
|
||||
</translate>
|
||||
<translate
|
||||
{{ $t('components.federation.FetchButton.connectionErrorMessage') }}
|
||||
</span>
|
||||
<span
|
||||
v-else-if="['invalid_json', 'invalid_jsonld', 'missing_jsonld_type'].indexOf(data.detail.error_code) > -1"
|
||||
>
|
||||
The remote server returned invalid JSON or JSON-LD data
|
||||
</translate>
|
||||
<translate
|
||||
{{ $t('components.federation.FetchButton.invalidJsonErrorMessage') }}
|
||||
</span>
|
||||
<span
|
||||
v-else-if="data.detail.error_code === 'validation'"
|
||||
>
|
||||
Data returned by the remote server had invalid or missing attributes
|
||||
</translate>
|
||||
<translate
|
||||
{{ $t('components.federation.FetchButton.invalidAttributesErrorMessage') }}
|
||||
</span>
|
||||
<span
|
||||
v-else-if="data.detail.error_code === 'unhandled'"
|
||||
>
|
||||
Unknown error
|
||||
</translate>
|
||||
<translate
|
||||
{{ $t('components.federation.FetchButton.unknownErrorMessage') }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
Unknown error
|
||||
</translate>
|
||||
{{ $t('components.federation.FetchButton.unknownErrorMessage') }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -183,7 +182,7 @@ const { start: startPolling } = useTimeoutFn(poll, 1000, { immediate: false })
|
|||
class="ui active inverted dimmer"
|
||||
>
|
||||
<div class="ui text loader">
|
||||
Requesting a fetch…
|
||||
{{ $t('components.federation.FetchButton.fetchRequestLoader') }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
@ -191,7 +190,7 @@ const { start: startPolling } = useTimeoutFn(poll, 1000, { immediate: false })
|
|||
class="ui active inverted dimmer"
|
||||
>
|
||||
<div class="ui text loader">
|
||||
Waiting for result…
|
||||
{{ $t('components.federation.FetchButton.awaitingResultLoader') }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
@ -200,7 +199,7 @@ const { start: startPolling } = useTimeoutFn(poll, 1000, { immediate: false })
|
|||
class="ui negative message"
|
||||
>
|
||||
<h4 class="header">
|
||||
Error while saving settings
|
||||
{{ $t('components.federation.FetchButton.loadingFailureMessage') }}
|
||||
</h4>
|
||||
<ul class="list">
|
||||
<li
|
||||
|
@ -217,23 +216,23 @@ const { start: startPolling } = useTimeoutFn(poll, 1000, { immediate: false })
|
|||
class="ui warning message"
|
||||
>
|
||||
<h4 class="header">
|
||||
Refresh pending
|
||||
{{ $t('components.federation.FetchButton.pendingRefreshHeader') }}
|
||||
</h4>
|
||||
<p>
|
||||
The refresh request hasn't been processed in time by our server. It will be processed later.
|
||||
{{ $t('components.federation.FetchButton.pendingRefreshMessage') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="ui basic cancel button">
|
||||
Close
|
||||
{{ $t('components.federation.FetchButton.closeButton') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="data && data.status === 'finished'"
|
||||
class="ui confirm success button"
|
||||
@click.prevent="showModal = false; emit('refresh')"
|
||||
>
|
||||
Close and reload page
|
||||
{{ $t('components.federation.FetchButton.reloadButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</semantic-modal>
|
||||
|
|
|
@ -64,7 +64,7 @@ fetchData()
|
|||
v-if="!isLoading && libraries.length === 0"
|
||||
class="ui subtitle"
|
||||
>
|
||||
No matching library.
|
||||
{{ $t('components.federation.LibraryWidget.noMatchMessage') }}
|
||||
</p>
|
||||
<div class="ui hidden divider" />
|
||||
<div class="ui cards">
|
||||
|
@ -90,7 +90,7 @@ fetchData()
|
|||
:class="['ui', 'basic', 'button']"
|
||||
@click="fetchData(nextPage)"
|
||||
>
|
||||
Show more
|
||||
{{ $t('components.federation.LibraryWidget.showMoreButton') }}
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
|
|
|
@ -27,8 +27,8 @@ const showPassword = ref(props.defaultShow)
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
title: t('Show/hide password'),
|
||||
copy: t('Copy')
|
||||
title: t('components.federation.PasswordInput.title'),
|
||||
copy: t('components.federation.PasswordInput.copyLabel')
|
||||
}))
|
||||
|
||||
const passwordInputType = computed(() => showPassword.value ? 'text' : 'password')
|
||||
|
@ -38,7 +38,7 @@ const { isSupported: canCopy, copy } = useClipboard({ source: value })
|
|||
const copyPassword = () => {
|
||||
copy()
|
||||
store.commit('ui/addMessage', {
|
||||
content: t('Text copied to clipboard!'),
|
||||
content: t('components.federation.PasswordInput.copySuccessMessage'),
|
||||
date: new Date()
|
||||
})
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ const publicLibraries = computed(() => libraries.value?.filter(library => librar
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
title: t('Album')
|
||||
title: t('components.library.AlbumBase.title')
|
||||
}))
|
||||
|
||||
const isLoading = ref(false)
|
||||
|
@ -177,24 +177,16 @@ const remove = async () => {
|
|||
/>
|
||||
<template v-if="totalTracks > 0">
|
||||
<div class="ui hidden very small divider" />
|
||||
<translate
|
||||
<span
|
||||
v-if="isSerie"
|
||||
|
||||
translate-plural="%{ count } episodes"
|
||||
:translate-n="totalTracks"
|
||||
:translate-params="{count: totalTracks}"
|
||||
>
|
||||
%{ count } episode
|
||||
</translate>
|
||||
<translate
|
||||
{{ $t('components.library.AlbumBase.episodeCount', {episode_count: totalTracks}) }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
|
||||
:translate-params="{count: totalTracks}"
|
||||
:translate-n="totalTracks"
|
||||
translate-plural="%{ count } tracks"
|
||||
>
|
||||
%{ count } track
|
||||
</translate>
|
||||
{{ $t('components.library.AlbumBase.trackCount', {tracks_count: totalTracks}) }}
|
||||
</span>
|
||||
</template>
|
||||
<div class="ui small hidden divider" />
|
||||
<play-button
|
||||
|
@ -263,26 +255,18 @@ const remove = async () => {
|
|||
v-if="object.release_date || (totalTracks > 0)"
|
||||
class="ui small hidden divider"
|
||||
/>
|
||||
<span v-if="object.release_date">{{ momentFormat(new Date(object.release_date ?? '1970-01-01'), 'Y') }} · </span>
|
||||
<span v-if="object.release_date">{{ momentFormat(new Date(object.release_date ?? '1970-01-01'), 'Y') }} · </span>
|
||||
<template v-if="totalTracks > 0">
|
||||
<translate
|
||||
<span
|
||||
v-if="isSerie"
|
||||
|
||||
translate-plural="%{ count } episodes"
|
||||
:translate-n="totalTracks"
|
||||
:translate-params="{count: totalTracks}"
|
||||
>
|
||||
%{ count } episode
|
||||
</translate>
|
||||
<translate
|
||||
{{ $t('components.library.AlbumBase.episodeCount', {episode_count: totalTracks}) }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
|
||||
:translate-params="{count: totalTracks}"
|
||||
:translate-n="totalTracks"
|
||||
translate-plural="%{ count } tracks"
|
||||
>
|
||||
%{ count } track
|
||||
</translate> ·
|
||||
{{ $t('components.library.AlbumBase.trackCount', {tracks_count: totalTracks}) }}
|
||||
</span> ·
|
||||
</template>
|
||||
<human-duration
|
||||
v-if="totalDuration > 0"
|
||||
|
@ -323,7 +307,7 @@ const remove = async () => {
|
|||
:to="{name: 'library.albums.edit', params: {id: object.id }}"
|
||||
>
|
||||
<i class="pencil icon" />
|
||||
Add a description…
|
||||
{{ $t('components.library.AlbumBase.addDescription') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -339,7 +323,7 @@ const remove = async () => {
|
|||
:to="{name: 'library.albums.edit', params: {id: object.id }}"
|
||||
>
|
||||
<i class="pencil icon" />
|
||||
Add a description…
|
||||
{{ $t('components.library.AlbumBase.addDescription') }}
|
||||
</router-link>
|
||||
</template>
|
||||
</div>
|
||||
|
|
|
@ -60,16 +60,12 @@ const paginatedDiscs = computed(() => props.object.tracks.slice(props.paginateBy
|
|||
</div>
|
||||
<div v-else-if="object">
|
||||
<h2 class="ui header">
|
||||
<translate
|
||||
v-if="isSerie"
|
||||
>
|
||||
Episodes
|
||||
</translate>
|
||||
<translate
|
||||
v-else
|
||||
>
|
||||
Tracks
|
||||
</translate>
|
||||
<span v-if="isSerie">
|
||||
{{ $t('components.library.AlbumDetail.episodesHeader') }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ $t('components.library.AlbumDetail.tracksHeader') }}
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
<channel-entries
|
||||
|
@ -91,12 +87,9 @@ const paginatedDiscs = computed(() => props.object.tracks.slice(props.paginateBy
|
|||
class="right floated mini inverted vibrant"
|
||||
:tracks="discs[index]"
|
||||
/>
|
||||
<translate
|
||||
tag="h3"
|
||||
:translate-params="{number: tracks[0]?.disc_number ?? index + 1}"
|
||||
>
|
||||
Volume %{ number }
|
||||
</translate>
|
||||
<h3>
|
||||
{{ $t('components.library.AlbumDetail.volumeNumber', {number: tracks[0].disc_number}) }}
|
||||
</h3>
|
||||
<track-table
|
||||
:is-album="true"
|
||||
:tracks="tracks"
|
||||
|
@ -135,13 +128,13 @@ const paginatedDiscs = computed(() => props.object.tracks.slice(props.paginateBy
|
|||
|
||||
<template v-if="!artist.channel && !isSerie">
|
||||
<h2>
|
||||
User libraries
|
||||
{{ $t('components.library.AlbumDetail.userLibraryHeader') }}
|
||||
</h2>
|
||||
<library-widget
|
||||
:url="'albums/' + object.id + '/libraries/'"
|
||||
@loaded="emit('libraries-loaded', $event)"
|
||||
>
|
||||
This album is present in the following libraries:
|
||||
{{ $t('components.library.AlbumDetail.userLibraryDescription') }}
|
||||
</library-widget>
|
||||
</template>
|
||||
</div>
|
||||
|
|
|
@ -35,7 +35,7 @@ const domain = computed(() => getDomain(props.object.fid))
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
more: t('More…')
|
||||
more: t('components.library.AlbumDropdown.moreLabel')
|
||||
}))
|
||||
|
||||
const isEmbedable = computed(() => (props.isChannel && props.artist?.channel?.actor) || props.publicLibraries.length)
|
||||
|
@ -53,7 +53,7 @@ const remove = () => emit('remove')
|
|||
v-model:show="showEmbedModal"
|
||||
>
|
||||
<h4 class="header">
|
||||
Embed this album on your website
|
||||
{{ $t('components.library.AlbumDropdown.embedModalHeader') }}
|
||||
</h4>
|
||||
<div class="scrolling content">
|
||||
<div class="description">
|
||||
|
@ -66,7 +66,7 @@ const remove = () => emit('remove')
|
|||
</div>
|
||||
<div class="actions">
|
||||
<button class="ui basic deny button">
|
||||
Cancel
|
||||
{{ $t('components.channels.AlbumModal.cancelButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</semantic-modal>
|
||||
|
@ -84,9 +84,7 @@ const remove = () => emit('remove')
|
|||
class="basic item"
|
||||
>
|
||||
<i class="external icon" />
|
||||
<translate
|
||||
:translate-params="{domain: domain}"
|
||||
>View on %{ domain }</translate>
|
||||
{{ $t('components.library.AlbumDropdown.domainViewLink') }}
|
||||
</a>
|
||||
|
||||
<div
|
||||
|
@ -96,7 +94,7 @@ const remove = () => emit('remove')
|
|||
@click="showEmbedModal = !showEmbedModal"
|
||||
>
|
||||
<i class="code icon" />
|
||||
Embed
|
||||
{{ $t('components.audio.EmbedWizard.copyButton') }}
|
||||
</div>
|
||||
<a
|
||||
v-if="isAlbum && musicbrainzUrl"
|
||||
|
@ -106,7 +104,7 @@ const remove = () => emit('remove')
|
|||
class="basic item"
|
||||
>
|
||||
<i class="external icon" />
|
||||
View on MusicBrainz
|
||||
{{ $t('components.library.AlbumDropdown.musicbrainzLink') }}
|
||||
</a>
|
||||
<a
|
||||
v-if="!isChannel && isAlbum"
|
||||
|
@ -116,7 +114,7 @@ const remove = () => emit('remove')
|
|||
class="basic item"
|
||||
>
|
||||
<i class="external icon" />
|
||||
Search on Discogs
|
||||
{{ $t('components.library.AlbumDropdown.discogsLink') }}
|
||||
</a>
|
||||
<router-link
|
||||
v-if="object.is_local"
|
||||
|
@ -124,7 +122,7 @@ const remove = () => emit('remove')
|
|||
class="basic item"
|
||||
>
|
||||
<i class="edit icon" />
|
||||
Edit
|
||||
{{ $t('components.library.AlbumDropdown.editButton') }}
|
||||
</router-link>
|
||||
<dangerous-button
|
||||
v-if="artist && $store.state.auth.authenticated && artist.channel && artist.attributed_to.full_username === $store.state.auth.fullUsername"
|
||||
|
@ -132,22 +130,22 @@ const remove = () => emit('remove')
|
|||
@confirm="remove()"
|
||||
>
|
||||
<i class="ui trash icon" />
|
||||
Delete…
|
||||
{{ $t('components.library.AlbumDropdown.deleteButton') }}
|
||||
<template #modal-header>
|
||||
<p>
|
||||
Delete this album?
|
||||
{{ $t('components.library.AlbumDropdown.deleteModalHeader') }}
|
||||
</p>
|
||||
</template>
|
||||
<template #modal-content>
|
||||
<div>
|
||||
<p>
|
||||
The album will be deleted, as well as any related files and data. This action is irreversible.
|
||||
{{ $t('components.library.AlbumDropdown.deleteModalMessage') }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<template #modal-confirm>
|
||||
<p>
|
||||
Delete
|
||||
{{ $t('components.library.AlbumDropdown.deleteButton') }}
|
||||
</p>
|
||||
</template>
|
||||
</dangerous-button>
|
||||
|
@ -168,7 +166,7 @@ const remove = () => emit('remove')
|
|||
:to="{name: 'manage.library.albums.detail', params: {id: object.id}}"
|
||||
>
|
||||
<i class="wrench icon" />
|
||||
Open in moderation interface
|
||||
{{ $t('components.library.AlbumDropdown.moderationLink') }}
|
||||
</router-link>
|
||||
<a
|
||||
v-if="$store.state.auth.profile && $store.state.auth.profile?.is_superuser"
|
||||
|
@ -178,7 +176,7 @@ const remove = () => emit('remove')
|
|||
rel="noopener noreferrer"
|
||||
>
|
||||
<i class="wrench icon" />
|
||||
View in Django's admin
|
||||
{{ $t('components.library.AlbumDropdown.djangoLink') }}
|
||||
</a>
|
||||
</div>
|
||||
</button>
|
||||
|
|
|
@ -22,22 +22,22 @@ const canEdit = store.state.auth.availablePermissions.library
|
|||
<section class="ui vertical stripe segment">
|
||||
<div class="ui text container">
|
||||
<h2>
|
||||
<translate
|
||||
<span
|
||||
v-if="canEdit"
|
||||
>
|
||||
Edit this album
|
||||
</translate>
|
||||
<translate
|
||||
{{ $t('components.library.AlbumEdit.editAlbumHeader') }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
Suggest an edit on this album
|
||||
</translate>
|
||||
{{ $t('components.library.AlbumEdit.suggestEditHeader') }}
|
||||
</span>
|
||||
</h2>
|
||||
<div
|
||||
v-if="!object.is_local"
|
||||
class="ui message"
|
||||
>
|
||||
This object is managed by another server, you cannot edit it.
|
||||
{{ $t('components.library.AlbumEdit.remoteObjectWarning') }}
|
||||
</div>
|
||||
<edit-form
|
||||
v-else
|
||||
|
|
|
@ -110,8 +110,8 @@ onMounted(() => $('.ui.dropdown').dropdown())
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
searchPlaceholder: t('Enter album title…'),
|
||||
title: t('Albums')
|
||||
searchPlaceholder: t('components.library.Albums.searchPlaceholder'),
|
||||
title: t('components.library.Albums.title')
|
||||
}))
|
||||
|
||||
const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value].sort((a, b) => a - b)))
|
||||
|
@ -121,7 +121,7 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
<main v-title="labels.title">
|
||||
<section class="ui vertical stripe segment">
|
||||
<h2 class="ui header">
|
||||
Browsing albums
|
||||
{{ $t('components.library.Albums.albumBrowseHeader') }}
|
||||
</h2>
|
||||
<form
|
||||
:class="['ui', {'loading': isLoading}, 'form']"
|
||||
|
@ -130,7 +130,7 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
<div class="fields">
|
||||
<div class="field">
|
||||
<label for="albums-search">
|
||||
Search
|
||||
{{ $t('components.library.Albums.searchLabel') }}
|
||||
</label>
|
||||
<div class="ui action input">
|
||||
<input
|
||||
|
@ -143,18 +143,18 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
<button
|
||||
class="ui icon button"
|
||||
type="submit"
|
||||
:aria-label="t('Search')"
|
||||
:aria-label="t('components.library.Albums.searchLabel')"
|
||||
>
|
||||
<i class="search icon" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="tags-search">Tags</label>
|
||||
<label for="tags-search">{{ $t('components.library.Albums.tagsLabel') }}</label>
|
||||
<tags-selector v-model="tags" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="album-ordering">Ordering</label>
|
||||
<label for="album-ordering">{{ $t('components.library.Albums.orderingLabel') }}</label>
|
||||
<select
|
||||
id="album-ordering"
|
||||
v-model="ordering"
|
||||
|
@ -170,22 +170,22 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="album-ordering-direction">Ordering direction</label>
|
||||
<label for="album-ordering-direction">{{ $t('components.library.Albums.orderingDirectionLabel') }}</label>
|
||||
<select
|
||||
id="album-ordering-direction"
|
||||
v-model="orderingDirection"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option value="+">
|
||||
Ascending
|
||||
{{ $t('components.library.Albums.ascendingOrdering') }}
|
||||
</option>
|
||||
<option value="-">
|
||||
Descending
|
||||
{{ $t('components.library.Albums.descendingOrdering') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="album-results">Results per page</label>
|
||||
<label for="album-results">{{ $t('components.library.Albums.resultsPerPageLabel') }}</label>
|
||||
<select
|
||||
id="album-results"
|
||||
v-model="paginateBy"
|
||||
|
@ -228,7 +228,7 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
>
|
||||
<div class="ui icon header">
|
||||
<i class="compact disc icon" />
|
||||
No results matching your query
|
||||
{{ $t('components.library.Albums.emptyStateMessage') }}
|
||||
</div>
|
||||
<router-link
|
||||
v-if="$store.state.auth.authenticated"
|
||||
|
@ -236,7 +236,7 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
class="ui success button labeled icon"
|
||||
>
|
||||
<i class="upload icon" />
|
||||
Add some music
|
||||
{{ $t('components.library.Albums.addMusicLink') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -59,7 +59,7 @@ const headerStyle = computed(() => cover.value?.urls.original
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
title: t('Artist')
|
||||
title: t('components.library.ArtistBase.title')
|
||||
}))
|
||||
|
||||
const isLoading = ref(false)
|
||||
|
@ -117,15 +117,9 @@ watch(() => props.id, fetchData, { immediate: true })
|
|||
v-if="albums"
|
||||
class="sub header"
|
||||
>
|
||||
<translate
|
||||
|
||||
tag="div"
|
||||
translate-plural="%{ count } tracks in %{ albumsCount } albums"
|
||||
:translate-n="totalTracks"
|
||||
:translate-params="{count: totalTracks, albumsCount: totalAlbums}"
|
||||
>
|
||||
%{ count } track in %{ albumsCount } albums
|
||||
</translate>
|
||||
<div>
|
||||
{{ $t('components.library.ArtistBase.tracksCount', {count: totalTracks, albums: totalAlbums}) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h2>
|
||||
|
@ -147,7 +141,7 @@ watch(() => props.id, fetchData, { immediate: true })
|
|||
class="vibrant"
|
||||
:artist="object"
|
||||
>
|
||||
Play all albums
|
||||
{{ $t('components.library.ArtistBase.playAllButton') }}
|
||||
</play-button>
|
||||
</div>
|
||||
|
||||
|
@ -156,7 +150,7 @@ watch(() => props.id, fetchData, { immediate: true })
|
|||
v-model:show="showEmbedModal"
|
||||
>
|
||||
<h4 class="header">
|
||||
Embed this artist work on your website
|
||||
{{ $t('components.library.ArtistBase.embedModalHeader') }}
|
||||
</h4>
|
||||
<div class="scrolling content">
|
||||
<div class="description">
|
||||
|
@ -168,7 +162,7 @@ watch(() => props.id, fetchData, { immediate: true })
|
|||
</div>
|
||||
<div class="actions">
|
||||
<button class="ui deny button">
|
||||
Cancel
|
||||
{{ $t('components.library.ArtistBase.cancelButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</semantic-modal>
|
||||
|
@ -177,7 +171,7 @@ watch(() => props.id, fetchData, { immediate: true })
|
|||
class="ui button"
|
||||
@click="dropdown.click()"
|
||||
>
|
||||
More…
|
||||
{{ $t('components.library.ArtistBase.moreButton') }}
|
||||
</button>
|
||||
<button
|
||||
ref="dropdown"
|
||||
|
@ -193,9 +187,7 @@ watch(() => props.id, fetchData, { immediate: true })
|
|||
class="basic item"
|
||||
>
|
||||
<i class="external icon" />
|
||||
<translate
|
||||
:translate-params="{domain: domain}"
|
||||
>View on %{ domain }</translate>
|
||||
{{ $t('components.library.ArtistBase.domainViewLink', {domain: domain}) }}
|
||||
</a>
|
||||
|
||||
<button
|
||||
|
@ -205,7 +197,7 @@ watch(() => props.id, fetchData, { immediate: true })
|
|||
@click.prevent="showEmbedModal = !showEmbedModal"
|
||||
>
|
||||
<i class="code icon" />
|
||||
Embed
|
||||
{{ $t('components.library.ArtistBase.embedButton') }}
|
||||
</button>
|
||||
<a
|
||||
:href="wikipediaUrl"
|
||||
|
@ -214,7 +206,7 @@ watch(() => props.id, fetchData, { immediate: true })
|
|||
class="basic item"
|
||||
>
|
||||
<i class="wikipedia w icon" />
|
||||
Search on Wikipedia
|
||||
{{ $t('components.library.ArtistBase.wikipediaLink') }}
|
||||
</a>
|
||||
<a
|
||||
v-if="musicbrainzUrl"
|
||||
|
@ -224,7 +216,7 @@ watch(() => props.id, fetchData, { immediate: true })
|
|||
class="basic item"
|
||||
>
|
||||
<i class="external icon" />
|
||||
View on MusicBrainz
|
||||
{{ $t('components.library.ArtistBase.musicbrainzLink') }}
|
||||
</a>
|
||||
<a
|
||||
:href="discogsUrl"
|
||||
|
@ -233,7 +225,7 @@ watch(() => props.id, fetchData, { immediate: true })
|
|||
class="basic item"
|
||||
>
|
||||
<i class="external icon" />
|
||||
Search on Discogs
|
||||
{{ $t('components.library.ArtistBase.discogsLink') }}
|
||||
</a>
|
||||
<router-link
|
||||
v-if="object.is_local"
|
||||
|
@ -241,7 +233,7 @@ watch(() => props.id, fetchData, { immediate: true })
|
|||
class="basic item"
|
||||
>
|
||||
<i class="edit icon" />
|
||||
Edit
|
||||
{{ $t('components.library.ArtistBase.editButton') }}
|
||||
</router-link>
|
||||
<div class="divider" />
|
||||
<div
|
||||
|
@ -261,7 +253,7 @@ watch(() => props.id, fetchData, { immediate: true })
|
|||
:to="{name: 'manage.library.artists.detail', params: {id: object.id}}"
|
||||
>
|
||||
<i class="wrench icon" />
|
||||
Open in moderation interface
|
||||
{{ $t('components.library.ArtistBase.moderationLink') }}
|
||||
</router-link>
|
||||
<a
|
||||
v-if="$store.state.auth.profile && $store.state.auth.profile.is_superuser"
|
||||
|
@ -271,7 +263,7 @@ watch(() => props.id, fetchData, { immediate: true })
|
|||
rel="noopener noreferrer"
|
||||
>
|
||||
<i class="wrench icon" />
|
||||
View in Django's admin
|
||||
{{ $t('components.library.ArtistBase.djangoLink') }}
|
||||
</a>
|
||||
</div>
|
||||
</button>
|
||||
|
|
|
@ -65,19 +65,19 @@ const loadMoreAlbums = async () => {
|
|||
<div class="ui hidden divider" />
|
||||
<div class="ui message">
|
||||
<p>
|
||||
You are currently hiding content related to this artist.
|
||||
{{ $t('components.library.ArtistDetail.hiddenContentMessage') }}
|
||||
</p>
|
||||
<router-link
|
||||
class="right floated"
|
||||
:to="{name: 'settings'}"
|
||||
>
|
||||
Review my filters
|
||||
{{ $t('components.library.ArtistDetail.reviewFiltersLink') }}
|
||||
</router-link>
|
||||
<button
|
||||
class="ui basic tiny button"
|
||||
@click="$store.dispatch('moderation/deleteContentFilter', contentFilter.uuid)"
|
||||
>
|
||||
Remove filter
|
||||
{{ $t('components.library.ArtistDetail.removeFilterButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -92,7 +92,7 @@ const loadMoreAlbums = async () => {
|
|||
class="ui vertical stripe segment"
|
||||
>
|
||||
<h2>
|
||||
Albums by this artist
|
||||
{{ $t('components.library.ArtistDetail.artistAlbumsHeader') }}
|
||||
</h2>
|
||||
<div class="ui cards app-cards">
|
||||
<album-card
|
||||
|
@ -107,7 +107,7 @@ const loadMoreAlbums = async () => {
|
|||
:class="['ui', {loading: isLoadingMoreAlbums}, 'button']"
|
||||
@click="loadMoreAlbums()"
|
||||
>
|
||||
Load more…
|
||||
{{ $t('components.library.ArtistDetail.loadMoreButton') }}
|
||||
</button>
|
||||
</section>
|
||||
<section
|
||||
|
@ -122,7 +122,7 @@ const loadMoreAlbums = async () => {
|
|||
>
|
||||
<template #header>
|
||||
<h2>
|
||||
New tracks by this artist
|
||||
{{ $t('components.library.ArtistDetail.newTracksHeader') }}
|
||||
</h2>
|
||||
<div class="ui hidden divider" />
|
||||
</template>
|
||||
|
@ -130,13 +130,13 @@ const loadMoreAlbums = async () => {
|
|||
</section>
|
||||
<section class="ui vertical stripe segment">
|
||||
<h2>
|
||||
User libraries
|
||||
{{ $t('components.library.ArtistDetail.userLibraryHeader') }}
|
||||
</h2>
|
||||
<library-widget
|
||||
:url="'artists/' + object.id + '/libraries/'"
|
||||
@loaded="emit('libraries-loaded', $event)"
|
||||
>
|
||||
This artist is present in the following libraries:
|
||||
{{ $t('components.library.ArtistDetail.userLibraryDescription') }}
|
||||
</library-widget>
|
||||
</section>
|
||||
</div>
|
||||
|
|
|
@ -22,22 +22,22 @@ const canEdit = store.state.auth.availablePermissions.library
|
|||
<section class="ui vertical stripe segment">
|
||||
<div class="ui text container">
|
||||
<h2>
|
||||
<translate
|
||||
<span
|
||||
v-if="canEdit"
|
||||
>
|
||||
Edit this artist
|
||||
</translate>
|
||||
<translate
|
||||
{{ $t('components.library.ArtistEdit.editArtistHeader') }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
Suggest an edit on this artist
|
||||
</translate>
|
||||
{{ $t('components.library.ArtistEdit.suggestEditHeader') }}
|
||||
</span>
|
||||
</h2>
|
||||
<div
|
||||
v-if="!object.is_local"
|
||||
class="ui message"
|
||||
>
|
||||
This object is managed by another server, you cannot edit it.
|
||||
{{ $t('components.library.ArtistEdit.remoteObjectWarning') }}
|
||||
</div>
|
||||
<edit-form
|
||||
v-else
|
||||
|
|
|
@ -122,7 +122,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
<main v-title="labels.title">
|
||||
<section class="ui vertical stripe segment">
|
||||
<h2 class="ui header">
|
||||
Browsing artists
|
||||
{{ $t('components.library.Artists.artistBrowseHeader') }}
|
||||
</h2>
|
||||
<form
|
||||
:class="['ui', {'loading': isLoading}, 'form']"
|
||||
|
@ -131,7 +131,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
<div class="fields">
|
||||
<div class="field">
|
||||
<label for="artist-search">
|
||||
Artist name
|
||||
{{ $t('components.library.Artists.searchLabel') }}
|
||||
</label>
|
||||
<div class="ui action input">
|
||||
<input
|
||||
|
@ -144,18 +144,18 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
<button
|
||||
class="ui icon button"
|
||||
type="submit"
|
||||
:aria-label="t('Search')"
|
||||
:aria-label="t('components.library.Artists.searchButton')"
|
||||
>
|
||||
<i class="search icon" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="tags-search">Tags</label>
|
||||
<label for="tags-search">{{ $t('components.library.Artists.tagsLabel') }}</label>
|
||||
<tags-selector v-model="tags" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="artist-ordering">Ordering</label>
|
||||
<label for="artist-ordering">{{ $t('components.library.Artists.orderingLabel') }}</label>
|
||||
<select
|
||||
id="artist-ordering"
|
||||
v-model="ordering"
|
||||
|
@ -171,22 +171,22 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="artist-ordering-direction">Ordering direction</label>
|
||||
<label for="artist-ordering-direction">{{ $t('components.library.Artists.orderingDirectionLabel') }}</label>
|
||||
<select
|
||||
id="artist-ordering-direction"
|
||||
v-model="orderingDirection"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option value="+">
|
||||
Ascending
|
||||
{{ $t('components.library.Artists.ascendingOrdering') }}
|
||||
</option>
|
||||
<option value="-">
|
||||
Descending
|
||||
{{ $t('components.library.Artists.descendingOrdering') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="artist-results">Results per page</label>
|
||||
<label for="artist-results">{{ $t('components.library.Artists.resultsPerPageLabel') }}</label>
|
||||
<select
|
||||
id="artist-results"
|
||||
v-model="paginateBy"
|
||||
|
@ -202,7 +202,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<span id="excludeHeader">Exclude Compilation Artists</span>
|
||||
<span id="excludeHeader">{{ $t('components.library.Artists.excludeCompilationArtistsLabel') }}</span>
|
||||
<div
|
||||
id="excludeCompilation"
|
||||
class="ui toggle checkbox"
|
||||
|
@ -217,7 +217,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
<label
|
||||
for="exclude-compilation"
|
||||
class="visually-hidden"
|
||||
>Exclude Compilation Artists</label>
|
||||
>{{ $t('components.library.Artists.excludeCompilationArtistsLabel') }}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -246,7 +246,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
>
|
||||
<div class="ui icon header">
|
||||
<i class="compact disc icon" />
|
||||
No results matching your query
|
||||
{{ $t('components.library.Artists.emptyStateMessage') }}
|
||||
</div>
|
||||
<router-link
|
||||
v-if="$store.state.auth.authenticated"
|
||||
|
@ -254,7 +254,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
class="ui success button labeled icon"
|
||||
>
|
||||
<i class="upload icon" />
|
||||
Add some music
|
||||
{{ $t('components.library.Artists.addMusicLink') }}
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="ui center aligned basic segment">
|
||||
|
|
|
@ -156,12 +156,7 @@ const approve = async (approved: boolean) => {
|
|||
<div class="content">
|
||||
<h4 class="header">
|
||||
<router-link :to="detailUrl">
|
||||
<translate
|
||||
|
||||
:translate-params="{id: obj.uuid.substring(0, 8)}"
|
||||
>
|
||||
Modification %{ id }
|
||||
</translate>
|
||||
{{ $t('components.library.EditCard.modificationHeader', {id: obj.uuid.substring(0, 8)}) }}
|
||||
</router-link>
|
||||
</h4>
|
||||
<div class="meta">
|
||||
|
@ -170,12 +165,7 @@ const approve = async (approved: boolean) => {
|
|||
:to="{name: 'library.tracks.detail', params: {id: obj.target.id }}"
|
||||
>
|
||||
<i class="music icon" />
|
||||
<translate
|
||||
|
||||
:translate-params="{id: obj.target.id, name: obj.target.repr}"
|
||||
>
|
||||
Track #%{ id } - %{ name }
|
||||
</translate>
|
||||
{{ $t('components.library.EditCard.trackLink', {id: obj.target.id, name: obj.target.repr}) }}
|
||||
</router-link>
|
||||
<br>
|
||||
<human-date
|
||||
|
@ -186,19 +176,19 @@ const approve = async (approved: boolean) => {
|
|||
<span class="right floated">
|
||||
<span v-if="obj.is_approved && obj.is_applied">
|
||||
<i class="success check icon" />
|
||||
Approved and applied
|
||||
{{ $t('components.library.EditCard.appliedStatus') }}
|
||||
</span>
|
||||
<span v-else-if="obj.is_approved">
|
||||
<i class="success check icon" />
|
||||
Approved
|
||||
{{ $t('components.library.EditCard.approvedStatus') }}
|
||||
</span>
|
||||
<span v-else-if="obj.is_approved === null">
|
||||
<i class="warning hourglass icon" />
|
||||
Pending review
|
||||
{{ $t('components.library.EditCard.pendingReviewStatus') }}
|
||||
</span>
|
||||
<span v-else-if="obj.is_approved === false">
|
||||
<i class="danger x icon" />
|
||||
Rejected
|
||||
{{ $t('components.library.EditCard.rejectedStatus') }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -217,13 +207,13 @@ const approve = async (approved: boolean) => {
|
|||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Field
|
||||
{{ $t('components.library.EditCard.fieldTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Old value
|
||||
{{ $t('components.library.EditCard.oldValueTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
New value
|
||||
{{ $t('components.library.EditCard.newValueTableHeader') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -253,7 +243,7 @@ const approve = async (approved: boolean) => {
|
|||
</template>
|
||||
</td>
|
||||
<td v-else>
|
||||
N/A
|
||||
{{ $t('components.library.EditCard.notApplicable') }}
|
||||
</td>
|
||||
|
||||
<td
|
||||
|
@ -311,36 +301,36 @@ const approve = async (approved: boolean) => {
|
|||
:class="['ui', {loading: isLoading}, 'success', 'basic', 'button']"
|
||||
@click="approve(true)"
|
||||
>
|
||||
Approve
|
||||
{{ $t('components.library.EditCard.approveButton') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="canApprove && obj.is_approved === null"
|
||||
:class="['ui', {loading: isLoading}, 'warning', 'basic', 'button']"
|
||||
@click="approve(false)"
|
||||
>
|
||||
Reject
|
||||
{{ $t('components.library.EditCard.rejectButton') }}
|
||||
</button>
|
||||
<dangerous-button
|
||||
v-if="canDelete"
|
||||
:class="['ui', {loading: isLoading}, 'basic danger button']"
|
||||
:action="remove"
|
||||
>
|
||||
Delete
|
||||
{{ $t('components.library.EditCard.deleteButton') }}
|
||||
<template #modal-header>
|
||||
<p>
|
||||
Delete this suggestion?
|
||||
{{ $t('components.library.EditCard.deleteSuggestionModalHeader') }}
|
||||
</p>
|
||||
</template>
|
||||
<template #modal-content>
|
||||
<div>
|
||||
<p>
|
||||
The suggestion will be completely removed, this action is irreversible.
|
||||
{{ $t('components.library.EditCard.deleteSuggestionModalMessage') }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<template #modal-confirm>
|
||||
<p>
|
||||
Delete
|
||||
{{ $t('components.library.EditCard.deleteButton') }}
|
||||
</p>
|
||||
</template>
|
||||
</dangerous-button>
|
||||
|
|
|
@ -46,7 +46,7 @@ const canEdit = computed(() => {
|
|||
})
|
||||
|
||||
const labels = computed(() => ({
|
||||
summaryPlaceholder: t('A short summary describing your changes.')
|
||||
summaryPlaceholder: t('components.library.EditForm.summaryPlaceholder')
|
||||
}))
|
||||
|
||||
const mutationsUrl = computed(() => props.objectType === 'track'
|
||||
|
@ -148,7 +148,7 @@ const resetField = (fieldId: string) => {
|
|||
<div v-if="submittedMutation">
|
||||
<div class="ui positive message">
|
||||
<h4 class="header">
|
||||
Your edit was successfully submitted.
|
||||
{{ $t('components.library.EditForm.submissionSuccessHeader') }}
|
||||
</h4>
|
||||
</div>
|
||||
<edit-card
|
||||
|
@ -159,7 +159,7 @@ const resetField = (fieldId: string) => {
|
|||
class="ui button"
|
||||
@click.prevent="submittedMutation = null"
|
||||
>
|
||||
Submit another edit
|
||||
{{ $t('components.library.EditForm.newEditButton') }}
|
||||
</button>
|
||||
</div>
|
||||
<div v-else>
|
||||
|
@ -171,27 +171,27 @@ const resetField = (fieldId: string) => {
|
|||
>
|
||||
<div>
|
||||
<template v-if="showPendingReview">
|
||||
Recent edits awaiting review
|
||||
{{ $t('components.library.EditForm.editsAwaitingReview') }}
|
||||
<button
|
||||
class="ui tiny basic right floated button"
|
||||
@click.prevent="showPendingReview = false"
|
||||
>
|
||||
Show all edits
|
||||
{{ $t('components.library.EditForm.showEditsButton') }}
|
||||
</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
Recent edits
|
||||
{{ $t('components.library.EditForm.recentEdits') }}
|
||||
<button
|
||||
class="ui tiny basic right floated button"
|
||||
@click.prevent="showPendingReview = true"
|
||||
>
|
||||
Restrict to unreviewed edits
|
||||
{{ $t('components.library.EditForm.onlyUnreviewed') }}
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
<template #empty-state>
|
||||
<empty-state>
|
||||
Suggest a change using the form below.
|
||||
{{ $t('components.library.EditForm.emptyStateMessage') }}
|
||||
</empty-state>
|
||||
</template>
|
||||
</edit-list>
|
||||
|
@ -206,7 +206,7 @@ const resetField = (fieldId: string) => {
|
|||
class="ui negative message"
|
||||
>
|
||||
<h4 class="header">
|
||||
Error while submitting edit
|
||||
{{ $t('components.library.EditForm.submissionFailureHeader') }}
|
||||
</h4>
|
||||
<ul class="list">
|
||||
<li
|
||||
|
@ -221,7 +221,7 @@ const resetField = (fieldId: string) => {
|
|||
v-if="!canEdit"
|
||||
class="ui message"
|
||||
>
|
||||
You don't have the permission to edit this object, but you can suggest changes. Once submitted, suggestions will be reviewed before approval.
|
||||
{{ $t('components.library.EditForm.noPermissionWarning') }}
|
||||
</div>
|
||||
<template v-if="values">
|
||||
<div
|
||||
|
@ -250,7 +250,7 @@ const resetField = (fieldId: string) => {
|
|||
class="ui fluid search dropdown"
|
||||
>
|
||||
<option :value="null">
|
||||
N/A
|
||||
{{ $t('components.library.EditForm.notApplicable') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="{ code, name } in licenses"
|
||||
|
@ -266,7 +266,7 @@ const resetField = (fieldId: string) => {
|
|||
@click.prevent="values[fieldConfig.id] = null"
|
||||
>
|
||||
<i class="x icon" />
|
||||
Clear
|
||||
{{ $t('components.library.EditForm.clearButton') }}
|
||||
</button>
|
||||
</template>
|
||||
<template v-else-if="fieldConfig.type === 'content'">
|
||||
|
@ -303,7 +303,7 @@ const resetField = (fieldId: string) => {
|
|||
@click.prevent="values[fieldConfig.id] = []"
|
||||
>
|
||||
<i class="x icon" />
|
||||
Clear
|
||||
{{ $t('components.library.EditForm.clearButton') }}
|
||||
</button>
|
||||
</template>
|
||||
<div v-if="fieldValuesChanged(fieldConfig.id)">
|
||||
|
@ -313,13 +313,13 @@ const resetField = (fieldId: string) => {
|
|||
@click.prevent="resetField(fieldConfig.id)"
|
||||
>
|
||||
<i class="undo icon" />
|
||||
Reset to initial value
|
||||
{{ $t('components.library.EditForm.resetButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="field">
|
||||
<label for="summary">Summary (optional)</label>
|
||||
<label for="summary">{{ $t('components.library.EditForm.summaryLabel') }}</label>
|
||||
<textarea
|
||||
id="change-summary"
|
||||
v-model="summary"
|
||||
|
@ -333,23 +333,23 @@ const resetField = (fieldId: string) => {
|
|||
class="ui left floated button"
|
||||
:to="{name: 'library.tracks.detail', params: {id: object.id }}"
|
||||
>
|
||||
Cancel
|
||||
{{ $t('components.library.EditForm.cancelButton') }}
|
||||
</router-link>
|
||||
<button
|
||||
:class="['ui', {'loading': isLoading}, 'right', 'floated', 'success', 'button']"
|
||||
type="submit"
|
||||
:disabled="isLoading || !mutationPayload"
|
||||
>
|
||||
<translate
|
||||
<span
|
||||
v-if="canEdit"
|
||||
>
|
||||
Submit and apply edit
|
||||
</translate>
|
||||
<translate
|
||||
{{ $t('components.library.EditForm.submitEditButton') }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
Submit suggestion
|
||||
</translate>
|
||||
{{ $t('components.library.EditForm.submitSuggestionButton') }}
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -43,13 +43,13 @@ const supportedExtensions = computed(() => store.state.ui.supportedExtensions)
|
|||
|
||||
const labels = computed(() => ({
|
||||
tooltips: {
|
||||
denied: t('Upload denied, ensure the file is not too big and that you have not reached your quota'),
|
||||
server: t('Cannot upload this file, ensure it is not too big'),
|
||||
network: t('A network error occurred while uploading this file'),
|
||||
timeout: t('Upload timeout, please try again'),
|
||||
retry: t('Retry'),
|
||||
denied: t('components.library.FileUpload.deniedTooltip'),
|
||||
server: t('components.library.FileUpload.serverTooltip'),
|
||||
network: t('components.library.FileUpload.networkTooltip'),
|
||||
timeout: t('components.library.FileUpload.timeoutTooltip'),
|
||||
retry: t('components.library.FileUpload.retryTooltip'),
|
||||
extension: t(
|
||||
'Invalid file type, ensure you are uploading an audio file. Supported file extensions are %{ extensions }',
|
||||
'components.library.FileUpload.extensionTooltip',
|
||||
{ extensions: supportedExtensions.value.join(', ') }
|
||||
)
|
||||
} as Record<string, string>
|
||||
|
@ -282,7 +282,7 @@ const retry = (files: Omit<VueUploadItem, 'xhr'>[]) => {
|
|||
useEventListener(window, 'beforeunload', (event) => {
|
||||
if (!hasActiveUploads.value) return null
|
||||
event.preventDefault()
|
||||
return (event.returnValue = t('This page is asking you to confirm that you want to leave - data you have entered may not be saved.'))
|
||||
return (event.returnValue = t('components.library.FileUpload.eventListenerMessage'))
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -294,12 +294,12 @@ useEventListener(window, 'beforeunload', (event) => {
|
|||
:class="['item', {active: currentTab === 'uploads'}]"
|
||||
@click.prevent="currentTab = 'uploads'"
|
||||
>
|
||||
Uploading
|
||||
{{ $t('components.library.FileUpload.uploadingStatus') }}
|
||||
<div
|
||||
v-if="files.length === 0"
|
||||
class="ui label"
|
||||
>
|
||||
0
|
||||
{{ $t('components.library.FileUpload.noActionableFiles') }}
|
||||
</div>
|
||||
<div
|
||||
v-else-if="files.length > uploadedFilesCount + erroredFilesCount"
|
||||
|
@ -319,12 +319,12 @@ useEventListener(window, 'beforeunload', (event) => {
|
|||
:class="['item', {active: currentTab === 'processing'}]"
|
||||
@click.prevent="currentTab = 'processing'"
|
||||
>
|
||||
Processing
|
||||
{{ $t('components.library.FileUpload.processingStatus') }}
|
||||
<div
|
||||
v-if="processableFiles === 0"
|
||||
class="ui label"
|
||||
>
|
||||
0
|
||||
{{ $t('components.library.FileUpload.noActionableFiles') }}
|
||||
</div>
|
||||
<div
|
||||
v-else-if="processableFiles > processedFilesCount"
|
||||
|
@ -344,7 +344,7 @@ useEventListener(window, 'beforeunload', (event) => {
|
|||
<div :class="['ui', {loading: isLoadingQuota}, 'container']">
|
||||
<div :class="['ui', {red: remainingSpace === 0}, {warning: remainingSpace > 0 && remainingSpace <= 50}, 'small', 'statistic']">
|
||||
<div class="label">
|
||||
Remaining storage space
|
||||
{{ $t('components.library.FileUpload.storageSpaceLabel') }}
|
||||
</div>
|
||||
<div class="value">
|
||||
{{ humanSize(remainingSpace * 1000 * 1000) }}
|
||||
|
@ -352,25 +352,25 @@ useEventListener(window, 'beforeunload', (event) => {
|
|||
</div>
|
||||
<div class="ui divider" />
|
||||
<h2 class="ui header">
|
||||
Upload music from '~/your local storage
|
||||
{{ $t('components.library.FileUpload.localUploadHeader') }}
|
||||
</h2>
|
||||
<div class="ui message">
|
||||
<p>
|
||||
You are about to upload music to your library. Before proceeding, please ensure that:
|
||||
{{ $t('components.library.FileUpload.localUploadMessage') }}
|
||||
</p>
|
||||
<ul>
|
||||
<li v-if="library.privacy_level != 'me'">
|
||||
You are not uploading copyrighted content in a public library, otherwise you may be infringing the law
|
||||
{{ $t('components.library.FileUpload.localUploadCopyright') }}
|
||||
</li>
|
||||
<li>
|
||||
The music files you are uploading are tagged properly.
|
||||
{{ $t('components.library.FileUpload.localUploadTag') }}
|
||||
<a
|
||||
href="http://picard.musicbrainz.org/"
|
||||
target="_blank"
|
||||
>We recommend using Picard for that purpose.</a>
|
||||
>{{ $t('components.library.FileUpload.localUploadPicardLink') }}</a>
|
||||
</li>
|
||||
<li>
|
||||
The music files you are uploading are in OGG, Flac, MP3 or AIFF format
|
||||
{{ $t('components.library.FileUpload.localUploadSupportedFormats') }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -388,16 +388,11 @@ useEventListener(window, 'beforeunload', (event) => {
|
|||
@input-file="inputFile"
|
||||
>
|
||||
<i class="upload icon" />
|
||||
Click to select files to upload or drag and drop files or directories
|
||||
{{ $t('components.library.FileUpload.uploadWidgetLabel') }}
|
||||
<br>
|
||||
<br>
|
||||
<i>
|
||||
<translate
|
||||
|
||||
:translate-params="{extensions: supportedExtensions.join(', ')}"
|
||||
>
|
||||
Supported extensions: %{ extensions }
|
||||
</translate>
|
||||
{{ $t('components.library.FileUpload.fileUploadSupportedFormats', {extensions: supportedExtensions.join(', ')}) }}
|
||||
</i>
|
||||
</file-upload-widget>
|
||||
</div>
|
||||
|
@ -410,16 +405,16 @@ useEventListener(window, 'beforeunload', (event) => {
|
|||
<thead>
|
||||
<tr>
|
||||
<th class="ten wide">
|
||||
Filename
|
||||
{{ $t('components.library.FileUpload.filenameTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Size
|
||||
{{ $t('components.library.FileUpload.sizeTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Status
|
||||
{{ $t('components.library.FileUpload.statusTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Actions
|
||||
{{ $t('components.library.FileUpload.actionsTableHeader') }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr v-if="retryableFiles.length > 1">
|
||||
|
@ -431,7 +426,7 @@ useEventListener(window, 'beforeunload', (event) => {
|
|||
class="ui right floated small basic button"
|
||||
@click.prevent="retry(retryableFiles)"
|
||||
>
|
||||
Retry failed uploads
|
||||
{{ $t('components.library.FileUpload.retryButton') }}
|
||||
</button>
|
||||
</th>
|
||||
</tr>
|
||||
|
@ -459,30 +454,30 @@ useEventListener(window, 'beforeunload', (event) => {
|
|||
v-else-if="file.success"
|
||||
class="ui success label"
|
||||
>
|
||||
<translate
|
||||
<span
|
||||
key="1"
|
||||
>Uploaded</translate>
|
||||
>{{ $t('components.library.FileUpload.uploadedStatusLabel') }}</span>
|
||||
</span>
|
||||
<span
|
||||
v-else-if="file.active"
|
||||
class="ui warning label"
|
||||
>
|
||||
<translate
|
||||
<span
|
||||
key="2"
|
||||
>
|
||||
Uploading…
|
||||
</translate>
|
||||
{{ $t('components.library.FileUpload.uploadingStatusLabel') }}
|
||||
</span>
|
||||
({{ parseFloat(file.progress ?? '0.00') }}%)
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
class="ui label"
|
||||
>
|
||||
<translate
|
||||
<span
|
||||
key="3"
|
||||
>
|
||||
Pending
|
||||
</translate>
|
||||
{{ $t('components.library.FileUpload.pendingStatusLabel') }}
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -511,7 +506,7 @@ useEventListener(window, 'beforeunload', (event) => {
|
|||
</div>
|
||||
<div class="ui divider" />
|
||||
<h2 class="ui header">
|
||||
Import music from your server
|
||||
{{ $t('components.library.FileUpload.serverUploadHeader') }}
|
||||
</h2>
|
||||
<div
|
||||
v-if="fsErrors.length > 0"
|
||||
|
@ -519,7 +514,7 @@ useEventListener(window, 'beforeunload', (event) => {
|
|||
class="ui negative message"
|
||||
>
|
||||
<h3 class="header">
|
||||
Error while launching import
|
||||
{{ $t('components.library.FileUpload.uploadFailureHeader') }}
|
||||
</h3>
|
||||
<ul class="list">
|
||||
<li
|
||||
|
@ -538,13 +533,13 @@ useEventListener(window, 'beforeunload', (event) => {
|
|||
/>
|
||||
<template v-if="fsStatus && fsStatus.import">
|
||||
<h3 class="ui header">
|
||||
Import status
|
||||
{{ $t('components.library.FileUpload.importStatusHeader') }}
|
||||
</h3>
|
||||
<p v-if="fsStatus.import.reference !== importReference">
|
||||
Results of your previous import:
|
||||
{{ $t('components.library.FileUpload.previousImportStatusMessage') }}
|
||||
</p>
|
||||
<p v-else>
|
||||
Results of your import:
|
||||
{{ $t('components.library.FileUpload.currentImportStatusMessage') }}
|
||||
</p>
|
||||
|
||||
<button
|
||||
|
@ -552,7 +547,7 @@ useEventListener(window, 'beforeunload', (event) => {
|
|||
class="ui button"
|
||||
@click="cancelFsScan"
|
||||
>
|
||||
Cancel
|
||||
{{ $t('components.library.FileUpload.cancelButton') }}
|
||||
</button>
|
||||
<fs-logs :data="fsStatus.import" />
|
||||
</template>
|
||||
|
|
|
@ -42,7 +42,7 @@ const handleClick = (entry: FSEntry) => {
|
|||
class="ui button"
|
||||
@click.prevent="emit('import')"
|
||||
>
|
||||
Import
|
||||
{{ $t('components.library.FsBrowser.importButton') }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="ui list component-fs-browser">
|
||||
|
|
|
@ -15,7 +15,7 @@ defineProps<Props>()
|
|||
class="ui active dimmer"
|
||||
>
|
||||
<div class="ui text loader">
|
||||
Import hasn't started yet
|
||||
{{ $t('components.library.FsLogs.emptyStateMessage') }}
|
||||
</div>
|
||||
</div>
|
||||
<template v-else>
|
||||
|
|
|
@ -26,7 +26,7 @@ const logger = useLogger()
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
title: t('Library')
|
||||
title: t('components.library.Home.title')
|
||||
}))
|
||||
|
||||
const isLoading = ref(false)
|
||||
|
@ -67,7 +67,7 @@ fetchData()
|
|||
:websocket-handlers="['Listen']"
|
||||
>
|
||||
<template #title>
|
||||
Recently listened
|
||||
{{ $t('components.library.Home.recentlyListenedLabel') }}
|
||||
</template>
|
||||
</track-widget>
|
||||
</div>
|
||||
|
@ -77,7 +77,7 @@ fetchData()
|
|||
:filters="{scope: scope, ordering: '-creation_date'}"
|
||||
>
|
||||
<template #title>
|
||||
Recently favorited
|
||||
{{ $t('components.library.Home.recentlyFavoritedLabel') }}
|
||||
</template>
|
||||
</track-widget>
|
||||
</div>
|
||||
|
@ -87,7 +87,7 @@ fetchData()
|
|||
:filters="{scope: scope, playable: true, ordering: '-modification_date'}"
|
||||
>
|
||||
<template #title>
|
||||
Playlists
|
||||
{{ $t('components.library.Home.playlistsLabel') }}
|
||||
</template>
|
||||
</playlist-widget>
|
||||
</div>
|
||||
|
@ -97,14 +97,14 @@ fetchData()
|
|||
<div class="column">
|
||||
<album-widget :filters="{scope: scope, playable: true, ordering: '-creation_date'}">
|
||||
<template #title>
|
||||
Recently added
|
||||
{{ $t('components.library.Home.recentlyAddedLabel') }}
|
||||
</template>
|
||||
</album-widget>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="scope === 'all'">
|
||||
<h3 class="ui header">
|
||||
New channels
|
||||
{{ $t('components.library.Home.newChannelsLabel') }}
|
||||
</h3>
|
||||
<channels-widget
|
||||
:show-modification-date="true"
|
||||
|
|
|
@ -58,11 +58,11 @@ const getErrorData = (upload: Upload) => {
|
|||
supportUrl: 'https://forum.funkwhale.audio/t/support',
|
||||
documentationUrl: `https://docs.funkwhale.audio/users/upload.html#${errorCode}`,
|
||||
label: errorCode === 'invalid_metadata'
|
||||
? t('Invalid metadata')
|
||||
: t('Unknown error'),
|
||||
? t('components.library.ImportStatusModal.invalidMetadataLabel')
|
||||
: t('components.library.ImportStatusModal.unknownErrorLabel'),
|
||||
detail: errorCode === 'invalid_metadata'
|
||||
? t('The metadata included in the file is invalid or some mandatory fields are missing.')
|
||||
: t('An unknown error occurred'),
|
||||
? t('components.library.ImportStatusModal.invalidMetadataMessage')
|
||||
: t('components.library.ImportStatusModal.unknownErrorMessage'),
|
||||
errorRows: errorCode === 'invalid_metadata'
|
||||
? getErrors(payload.detail ?? {})
|
||||
: [],
|
||||
|
@ -77,7 +77,7 @@ const getErrorData = (upload: Upload) => {
|
|||
<template>
|
||||
<semantic-modal v-model:show="show">
|
||||
<h4 class="header">
|
||||
Import detail
|
||||
{{ $t('components.library.ImportStatusModal.importDetailHeader') }}
|
||||
</h4>
|
||||
<div
|
||||
v-if="Object.keys(upload).length > 0"
|
||||
|
@ -88,33 +88,33 @@ const getErrorData = (upload: Upload) => {
|
|||
v-if="upload.import_status === 'pending'"
|
||||
class="ui message"
|
||||
>
|
||||
Upload is still pending and will soon be processed by the server.
|
||||
{{ $t('components.library.ImportStatusModal.importDetailMessage') }}
|
||||
</div>
|
||||
<div
|
||||
v-if="upload.import_status === 'finished'"
|
||||
class="ui success message"
|
||||
>
|
||||
Upload was successfully processed by the server.
|
||||
{{ $t('components.library.ImportStatusModal.importSuccessMessage') }}
|
||||
</div>
|
||||
<div
|
||||
v-if="upload.import_status === 'skipped'"
|
||||
role="alert"
|
||||
class="ui warning message"
|
||||
>
|
||||
Upload was skipped because a similar one is already available in one of your libraries.
|
||||
{{ $t('components.library.ImportStatusModal.importSkippedWarning') }}
|
||||
</div>
|
||||
<div
|
||||
v-if="upload.import_status === 'errored'"
|
||||
class="ui error message"
|
||||
>
|
||||
An error occurred during upload processing. You will find more information below.
|
||||
{{ $t('components.library.ImportStatusModal.importFailureMessage') }}
|
||||
</div>
|
||||
<template v-if="upload.import_status === 'errored'">
|
||||
<table class="ui very basic collapsing celled table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Error type
|
||||
{{ $t('components.library.ImportStatusModal.errorType') }}
|
||||
</td>
|
||||
<td>
|
||||
{{ getErrorData(upload).label }}
|
||||
|
@ -122,7 +122,7 @@ const getErrorData = (upload: Upload) => {
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Error detail
|
||||
{{ $t('components.library.ImportStatusModal.errorDetail') }}
|
||||
</td>
|
||||
<td>
|
||||
{{ getErrorData(upload).detail }}
|
||||
|
@ -138,7 +138,7 @@ const getErrorData = (upload: Upload) => {
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Getting help
|
||||
{{ $t('components.library.ImportStatusModal.gettingHelp') }}
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
|
@ -147,7 +147,7 @@ const getErrorData = (upload: Upload) => {
|
|||
:href="getErrorData(upload).documentationUrl"
|
||||
target="_blank"
|
||||
>
|
||||
Read our documentation for this error
|
||||
{{ $t('components.library.ImportStatusModal.documentationLink') }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
|
@ -155,7 +155,7 @@ const getErrorData = (upload: Upload) => {
|
|||
:href="getErrorData(upload).supportUrl"
|
||||
target="_blank"
|
||||
>
|
||||
Open a support thread (include the debug information below in your message)
|
||||
{{ $t('components.library.ImportStatusModal.supportLink') }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -163,7 +163,7 @@ const getErrorData = (upload: Upload) => {
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Debug information
|
||||
{{ $t('components.library.ImportStatusModal.debugInformation') }}
|
||||
</td>
|
||||
<td>
|
||||
<div class="ui form">
|
||||
|
@ -182,7 +182,7 @@ const getErrorData = (upload: Upload) => {
|
|||
</div>
|
||||
<div class="actions">
|
||||
<button class="ui deny button">
|
||||
Close
|
||||
{{ $t('components.library.ImportStatusModal.closeButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</semantic-modal>
|
||||
|
|
|
@ -112,8 +112,8 @@ onMounted(() => $('.ui.dropdown').dropdown())
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
searchPlaceholder: t('Search…'),
|
||||
title: t('Podcasts')
|
||||
searchPlaceholder: t('components.library.Podcasts.searchPlaceholder'),
|
||||
title: t('components.library.Podcasts.title')
|
||||
}))
|
||||
|
||||
const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value].sort((a, b) => a - b)))
|
||||
|
@ -123,7 +123,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
<main v-title="labels.title">
|
||||
<section class="ui vertical stripe segment">
|
||||
<h2 class="ui header">
|
||||
Browsing podcasts
|
||||
{{ $t('components.library.Podcasts.podcastBrowseHeader') }}
|
||||
</h2>
|
||||
<form
|
||||
:class="['ui', {'loading': isLoading}, 'form']"
|
||||
|
@ -132,7 +132,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
<div class="fields">
|
||||
<div class="field">
|
||||
<label for="artist-search">
|
||||
Podcast title
|
||||
{{ $t('components.library.Podcasts.searchLabel') }}
|
||||
</label>
|
||||
<div class="ui action input">
|
||||
<input
|
||||
|
@ -145,18 +145,18 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
<button
|
||||
class="ui icon button"
|
||||
type="submit"
|
||||
:aria-label="t('Search')"
|
||||
:aria-label="t('components.library.Podcasts.searchButton')"
|
||||
>
|
||||
<i class="search icon" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="tags-search">Tags</label>
|
||||
<label for="tags-search">{{ $t('components.library.Podcasts.tagsLabel') }}</label>
|
||||
<tags-selector v-model="tags" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="artist-ordering">Ordering</label>
|
||||
<label for="artist-ordering">{{ $t('components.library.Podcasts.orderingLabel') }}</label>
|
||||
<select
|
||||
id="artist-ordering"
|
||||
v-model="ordering"
|
||||
|
@ -172,22 +172,22 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="artist-ordering-direction">Ordering direction</label>
|
||||
<label for="artist-ordering-direction">{{ $t('components.library.Podcasts.orderingDirectionLabel') }}</label>
|
||||
<select
|
||||
id="artist-ordering-direction"
|
||||
v-model="orderingDirection"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option value="+">
|
||||
Ascending
|
||||
{{ $t('components.library.Podcasts.ascendingOrdering') }}
|
||||
</option>
|
||||
<option value="-">
|
||||
Descending
|
||||
{{ $t('components.library.Podcasts.descendingOrdering') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="artist-results">Results per page</label>
|
||||
<label for="artist-results">{{ $t('components.library.Podcasts.resultsPerPageLabel') }}</label>
|
||||
<select
|
||||
id="artist-results"
|
||||
v-model="paginateBy"
|
||||
|
@ -228,7 +228,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
>
|
||||
<div class="ui icon header">
|
||||
<i class="podcast icon" />
|
||||
No results matching your query
|
||||
{{ $t('components.library.Podcasts.emptyStateMessage') }}
|
||||
</div>
|
||||
<router-link
|
||||
v-if="$store.state.auth.authenticated"
|
||||
|
@ -236,7 +236,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
class="ui success button labeled icon"
|
||||
>
|
||||
<i class="upload icon" />
|
||||
Create a Channel
|
||||
{{ $t('components.library.Podcasts.addChannelLink') }}
|
||||
</router-link>
|
||||
<h1
|
||||
v-if="$store.state.auth.authenticated"
|
||||
|
@ -245,7 +245,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
<div class="actions">
|
||||
<a @click.stop.prevent="showSubscribeModal = true">
|
||||
<i class="plus icon" />
|
||||
Subscribe to feed
|
||||
{{ $t('components.library.Podcasts.subscribeLink') }}
|
||||
</a>
|
||||
</div>
|
||||
</h1>
|
||||
|
@ -265,7 +265,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
:fullscreen="false"
|
||||
>
|
||||
<h2 class="header">
|
||||
Subscription
|
||||
{{ $t('components.library.Podcasts.subscriptionModalHeader') }}
|
||||
</h2>
|
||||
<div
|
||||
ref="modalContent"
|
||||
|
@ -281,7 +281,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
</div>
|
||||
<div class="actions">
|
||||
<button class="ui basic deny button">
|
||||
Cancel
|
||||
{{ $t('components.library.Podcasts.cancelButton') }}
|
||||
</button>
|
||||
<button
|
||||
form="remote-search"
|
||||
|
@ -289,7 +289,7 @@ const paginateOptions = computed(() => sortedUniq([12, 30, 50, paginateBy.value]
|
|||
class="ui primary button"
|
||||
>
|
||||
<i class="bookmark icon" />
|
||||
Subscribe
|
||||
{{ $t('components.library.Podcasts.subscribeButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</semantic-modal>
|
||||
|
|
|
@ -101,8 +101,8 @@ onMounted(() => $('.ui.dropdown').dropdown())
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
searchPlaceholder: t('Enter a radio name…'),
|
||||
title: t('Radios')
|
||||
searchPlaceholder: t('components.library.Radios.searchPlaceholder'),
|
||||
title: t('components.library.Podcasts.title')
|
||||
}))
|
||||
|
||||
const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value].sort((a, b) => a - b)))
|
||||
|
@ -112,12 +112,12 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
<main v-title="labels.title">
|
||||
<section class="ui vertical stripe segment">
|
||||
<h2 class="ui header">
|
||||
Browsing radios
|
||||
{{ $t('components.library.Radios.radioBrowseHeader') }}
|
||||
</h2>
|
||||
<div class="ui hidden divider" />
|
||||
<div class="ui row">
|
||||
<h3 class="ui header">
|
||||
Instance radios
|
||||
{{ $t('components.library.Radios.instanceRadioHeader') }}
|
||||
</h3>
|
||||
<div class="ui cards">
|
||||
<radio-card
|
||||
|
@ -140,14 +140,14 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
|
||||
<div class="ui hidden divider" />
|
||||
<h3 class="ui header">
|
||||
User radios
|
||||
{{ $t('components.library.Radios.userRadioHeader') }}
|
||||
</h3>
|
||||
<router-link
|
||||
v-if="isAuthenticated"
|
||||
class="ui success button"
|
||||
to="/library/radios/build"
|
||||
>
|
||||
Create your own radio
|
||||
{{ $t('components.library.Radios.createRadioLink') }}
|
||||
</router-link>
|
||||
<div class="ui hidden divider" />
|
||||
<form
|
||||
|
@ -156,7 +156,7 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
>
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
<label for="radios-search">Search</label>
|
||||
<label for="radios-search">{{ $t('components.library.Radios.searchLabel') }}</label>
|
||||
<div class="ui action input">
|
||||
<input
|
||||
id="radios-search"
|
||||
|
@ -168,14 +168,14 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
<button
|
||||
class="ui icon button"
|
||||
type="submit"
|
||||
:aria-label="t('Search')"
|
||||
:aria-label="t('components.library.Radios.searchButton')"
|
||||
>
|
||||
<i class="search icon" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="radios-ordering">Ordering</label>
|
||||
<label for="radios-ordering">{{ $t('components.library.Radios.orderingLabel') }}</label>
|
||||
<select
|
||||
id="radios-ordering"
|
||||
v-model="ordering"
|
||||
|
@ -191,22 +191,22 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="radios-ordering-direction">Order</label>
|
||||
<label for="radios-ordering-direction">{{ $t('components.library.Radios.orderingDirectionLabel') }}</label>
|
||||
<select
|
||||
id="radios-ordering-direction"
|
||||
v-model="orderingDirection"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option value="+">
|
||||
Ascending
|
||||
{{ $t('components.library.Radios.ascendingOrdering') }}
|
||||
</option>
|
||||
<option value="-">
|
||||
Descending
|
||||
{{ $t('components.library.Radios.descendingOrdering') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="radios-results">Results per page</label>
|
||||
<label for="radios-results">{{ $t('components.library.Radios.resultsPerPageLabel') }}</label>
|
||||
<select
|
||||
id="radios-results"
|
||||
v-model="paginateBy"
|
||||
|
@ -230,7 +230,7 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
>
|
||||
<div class="ui icon header">
|
||||
<i class="feed icon" />
|
||||
No results matching your query
|
||||
{{ $t('components.library.Radios.emptyStateMessage') }}
|
||||
</div>
|
||||
<router-link
|
||||
v-if="$store.state.auth.authenticated"
|
||||
|
@ -238,7 +238,7 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
|
|||
class="ui success button labeled icon"
|
||||
>
|
||||
<i class="rss icon" />
|
||||
Create a radio
|
||||
{{ $t('components.library.Radios.addRadioLink') }}
|
||||
</router-link>
|
||||
</div>
|
||||
<div
|
||||
|
|
|
@ -36,7 +36,7 @@ const labels = computed(() => ({
|
|||
:to="{name: 'manage.library.tags.detail', params: {id: id}}"
|
||||
>
|
||||
<i class="wrench icon" />
|
||||
Open in moderation interface
|
||||
{{ $t('components.library.TagDetail.moderationLink') }}
|
||||
</router-link>
|
||||
|
||||
<div class="ui hidden divider" />
|
||||
|
@ -48,14 +48,14 @@ const labels = computed(() => ({
|
|||
>
|
||||
<template #title>
|
||||
<router-link :to="{name: 'library.artists.browse', query: {tag: id}}">
|
||||
Artists
|
||||
{{ $t('components.library.TagDetail.artistsLabel') }}
|
||||
</router-link>
|
||||
</template>
|
||||
</artist-widget>
|
||||
<div class="ui hidden divider" />
|
||||
<div class="ui hidden divider" />
|
||||
<h3 class="ui header">
|
||||
Channels
|
||||
{{ $t('components.library.TagDetail.channelsLabel') }}
|
||||
</h3>
|
||||
<channels-widget
|
||||
:key="'channels' + id"
|
||||
|
@ -73,7 +73,7 @@ const labels = computed(() => ({
|
|||
>
|
||||
<template #title>
|
||||
<router-link :to="{name: 'library.albums.browse', query: {tag: id}}">
|
||||
Albums
|
||||
{{ $t('components.library.TagDetail.albumsLabel') }}
|
||||
</router-link>
|
||||
</template>
|
||||
</album-widget>
|
||||
|
@ -89,7 +89,7 @@ const labels = computed(() => ({
|
|||
:filters="{playable: true, ordering: '-creation_date', tag: id}"
|
||||
>
|
||||
<template #title>
|
||||
Tracks
|
||||
{{ $t('components.library.TagDetail.tracksLabel') }}
|
||||
</template>
|
||||
</track-widget>
|
||||
<div class="ui clearing hidden divider" />
|
||||
|
|
|
@ -99,7 +99,7 @@ onMounted(async () => {
|
|||
class="search"
|
||||
>
|
||||
<div class="default text">
|
||||
Search…
|
||||
{{ $t('components.library.TagSelector.searchPlaceholder') }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -89,9 +89,9 @@ const subtitle = computed(() => {
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
title: t('Track'),
|
||||
download: t('Download'),
|
||||
more: t('More…')
|
||||
title: t('components.library.TrackBase.title'),
|
||||
download: t('components.library.TrackBase.downloadLabel'),
|
||||
more: t('components.library.TrackBase.moreLabel')
|
||||
}))
|
||||
|
||||
const isLoading = ref(false)
|
||||
|
@ -155,7 +155,7 @@ const remove = async () => {
|
|||
class="vibrant"
|
||||
:track="track"
|
||||
>
|
||||
Play
|
||||
{{ $t('components.library.TrackBase.playButton') }}
|
||||
</play-button>
|
||||
|
||||
<track-favorite-icon
|
||||
|
@ -185,7 +185,7 @@ const remove = async () => {
|
|||
v-model:show="showEmbedModal"
|
||||
>
|
||||
<h4 class="header">
|
||||
Embed this track on your website
|
||||
{{ $t('components.library.TrackBase.embedModalHeader') }}
|
||||
</h4>
|
||||
<div class="scrolling content">
|
||||
<div class="description">
|
||||
|
@ -197,7 +197,7 @@ const remove = async () => {
|
|||
</div>
|
||||
<div class="actions">
|
||||
<button class="ui basic deny button">
|
||||
Cancel
|
||||
{{ $t('components.library.TrackBase.cancelButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</semantic-modal>
|
||||
|
@ -218,9 +218,7 @@ const remove = async () => {
|
|||
class="basic item"
|
||||
>
|
||||
<i class="external icon" />
|
||||
<translate
|
||||
:translate-params="{domain: domain}"
|
||||
>View on %{ domain }</translate>
|
||||
{{ $t('components.library.TrackBase.domainViewLink', {domain: domain}) }}
|
||||
</a>
|
||||
<div
|
||||
v-if="isEmbedable"
|
||||
|
@ -229,7 +227,7 @@ const remove = async () => {
|
|||
@click="showEmbedModal = !showEmbedModal"
|
||||
>
|
||||
<i class="code icon" />
|
||||
Embed
|
||||
{{ $t('components.library.TrackBase.embedButton') }}
|
||||
</div>
|
||||
<a
|
||||
:href="wikipediaUrl"
|
||||
|
@ -238,7 +236,7 @@ const remove = async () => {
|
|||
class="basic item"
|
||||
>
|
||||
<i class="wikipedia w icon" />
|
||||
Search on Wikipedia
|
||||
{{ $t('components.library.TrackBase.wikipediaLink') }}
|
||||
</a>
|
||||
<a
|
||||
v-if="discogsUrl"
|
||||
|
@ -248,7 +246,7 @@ const remove = async () => {
|
|||
class="basic item"
|
||||
>
|
||||
<i class="external icon" />
|
||||
Search on Discogs
|
||||
{{ $t('components.library.TrackBase.discogsLink') }}
|
||||
</a>
|
||||
<router-link
|
||||
v-if="track.is_local"
|
||||
|
@ -256,7 +254,7 @@ const remove = async () => {
|
|||
class="basic item"
|
||||
>
|
||||
<i class="edit icon" />
|
||||
Edit
|
||||
{{ $t('components.library.TrackBase.editButton') }}
|
||||
</router-link>
|
||||
<dangerous-button
|
||||
v-if="artist && $store.state.auth.authenticated && artist.channel && artist.attributed_to.full_username === $store.state.auth.fullUsername"
|
||||
|
@ -264,22 +262,22 @@ const remove = async () => {
|
|||
@confirm="remove()"
|
||||
>
|
||||
<i class="ui trash icon" />
|
||||
Delete…
|
||||
{{ $t('components.library.TrackBase.deleteButton') }}
|
||||
<template #modal-header>
|
||||
<p>
|
||||
Delete this track?
|
||||
{{ $t('components.library.TrackBase.deleteModalHeader') }}
|
||||
</p>
|
||||
</template>
|
||||
<template #modal-content>
|
||||
<div>
|
||||
<p>
|
||||
The track will be deleted, as well as any related files and data. This action is irreversible.
|
||||
{{ $t('components.library.TrackBase.deleteModalMessage') }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<template #modal-confirm>
|
||||
<p>
|
||||
Delete
|
||||
{{ $t('components.library.TrackBase.deleteButton') }}
|
||||
</p>
|
||||
</template>
|
||||
</dangerous-button>
|
||||
|
@ -300,7 +298,7 @@ const remove = async () => {
|
|||
:to="{name: 'manage.library.tracks.detail', params: {id: track.id}}"
|
||||
>
|
||||
<i class="wrench icon" />
|
||||
Open in moderation interface
|
||||
{{ $t('components.library.TrackBase.moderationLink') }}
|
||||
</router-link>
|
||||
<a
|
||||
v-if="$store.state.auth.profile && $store.state.auth.profile.is_superuser"
|
||||
|
@ -310,7 +308,7 @@ const remove = async () => {
|
|||
rel="noopener noreferrer"
|
||||
>
|
||||
<i class="wrench icon" />
|
||||
View in Django's admin
|
||||
{{ $t('components.library.TrackBase.djangoLink') }}
|
||||
</a>
|
||||
</div>
|
||||
</button>
|
||||
|
|
|
@ -76,82 +76,82 @@ watchEffect(() => {
|
|||
class="ui fluid image track-cover-image"
|
||||
>
|
||||
<h3 class="ui header">
|
||||
<translate
|
||||
<span
|
||||
v-if="track.artist?.content_category === 'music'"
|
||||
>
|
||||
Track Details
|
||||
</translate>
|
||||
<translate
|
||||
{{ $t('components.library.TrackDetail.trackDetails') }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
Episode Details
|
||||
</translate>
|
||||
{{ $t('components.library.TrackDetail.episodeDetails') }}
|
||||
</span>
|
||||
</h3>
|
||||
<table class="ui basic table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Duration
|
||||
{{ $t('components.library.TrackDetail.durationTableHeader') }}
|
||||
</td>
|
||||
<td class="right aligned">
|
||||
<template v-if="upload.duration">
|
||||
{{ time.parse(upload.duration) }}
|
||||
</template>
|
||||
<translate
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
N/A
|
||||
</translate>
|
||||
{{ $t('components.library.TrackDetail.notApplicable') }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Size
|
||||
{{ $t('components.library.TrackDetail.sizeTableLabel') }}
|
||||
</td>
|
||||
<td class="right aligned">
|
||||
<template v-if="upload.size">
|
||||
{{ humanSize(upload.size) }}
|
||||
</template>
|
||||
<translate
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
N/A
|
||||
</translate>
|
||||
{{ $t('components.library.TrackDetail.notApplicable') }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Codec
|
||||
{{ $t('components.library.TrackDetail.codecTableLabel') }}
|
||||
</td>
|
||||
<td class="right aligned">
|
||||
<template v-if="upload.extension">
|
||||
{{ upload.extension }}
|
||||
</template>
|
||||
<translate
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
N/A
|
||||
</translate>
|
||||
{{ $t('components.library.TrackDetail.notApplicable') }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Bitrate
|
||||
{{ $t('components.library.TrackDetail.bitrateTableLabel') }}
|
||||
</td>
|
||||
<td class="right aligned">
|
||||
<template v-if="upload.bitrate">
|
||||
{{ humanSize(upload.bitrate) }}/s
|
||||
{{ $t('components.library.TrackDetail.uploadBitrateTableLabel', {bitrate: humanSize(upload.bitrate)}) }}
|
||||
</template>
|
||||
<translate
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
N/A
|
||||
</translate>
|
||||
{{ $t('components.library.TrackDetail.notApplicable') }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Downloads
|
||||
{{ $t('components.library.TrackDetail.downloadsTableLabel') }}
|
||||
</td>
|
||||
<td class="right aligned">
|
||||
{{ track.downloads_count }}
|
||||
|
@ -172,13 +172,13 @@ watchEffect(() => {
|
|||
:can-update="false"
|
||||
/>
|
||||
<h2 class="ui header">
|
||||
Release Details
|
||||
{{ $t('components.library.TrackDetail.releaseDetailsHeader') }}
|
||||
</h2>
|
||||
<table class="ui basic table ellipsis-rows">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Artist
|
||||
{{ $t('components.library.TrackDetail.artistTableLabel') }}
|
||||
</td>
|
||||
<td class="right aligned">
|
||||
<router-link :to="{name: 'library.artists.detail', params: {id: track.artist?.id}}">
|
||||
|
@ -188,16 +188,16 @@ watchEffect(() => {
|
|||
</tr>
|
||||
<tr v-if="track.album">
|
||||
<td>
|
||||
<translate
|
||||
<span
|
||||
v-if="track.album.artist.content_category === 'music'"
|
||||
>
|
||||
Album
|
||||
</translate>
|
||||
<translate
|
||||
{{ $t('components.library.TrackDetail.albumTableLabel') }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
Serie
|
||||
</translate>
|
||||
{{ $t('components.library.TrackDetail.seriesTableLabel') }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="right aligned">
|
||||
<router-link :to="{name: 'library.albums.detail', params: {id: track.album.id}}">
|
||||
|
@ -207,20 +207,20 @@ watchEffect(() => {
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Year
|
||||
{{ $t('components.library.TrackDetail.yearTableLabel') }}
|
||||
</td>
|
||||
<td class="right aligned">
|
||||
<template v-if="track.album && track.album.release_date">
|
||||
{{ momentFormat(new Date(track.album.release_date), 'Y') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
N/A
|
||||
{{ $t('components.library.TrackDetail.notApplicable') }}
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Copyright
|
||||
{{ $t('components.library.TrackDetail.copyrightTableLabel') }}
|
||||
</td>
|
||||
<td class="right aligned">
|
||||
<span
|
||||
|
@ -228,13 +228,13 @@ watchEffect(() => {
|
|||
:title="track.copyright"
|
||||
>{{ truncate(track.copyright, 50) }}</span>
|
||||
<template v-else>
|
||||
N/A
|
||||
{{ $t('components.library.TrackDetail.notApplicable') }}
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
License
|
||||
{{ $t('components.library.TrackDetail.licenseTableLabel') }}
|
||||
</td>
|
||||
<td class="right aligned">
|
||||
<a
|
||||
|
@ -243,16 +243,16 @@ watchEffect(() => {
|
|||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>{{ license.name }}</a>
|
||||
<translate
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
N/A
|
||||
</translate>
|
||||
{{ $t('components.library.TrackDetail.notApplicable') }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="!track.is_local">
|
||||
<td>
|
||||
URL
|
||||
{{ $t('components.library.TrackDetail.urlTableLabel') }}
|
||||
</td>
|
||||
<td :title="track.fid">
|
||||
<a
|
||||
|
@ -273,10 +273,10 @@ watchEffect(() => {
|
|||
rel="noreferrer noopener"
|
||||
>
|
||||
<i class="external icon" />
|
||||
View on MusicBrainz
|
||||
{{ $t('components.library.TrackDetail.musicbrainzLink') }}
|
||||
</a>
|
||||
<h2 class="ui header">
|
||||
Related Playlists
|
||||
{{ $t('components.library.TrackDetail.relatedPlaylistsHeader') }}
|
||||
</h2>
|
||||
<playlist-widget
|
||||
:url="'playlists/'"
|
||||
|
@ -284,13 +284,13 @@ watchEffect(() => {
|
|||
/>
|
||||
|
||||
<h2 class="ui header">
|
||||
Related Libraries
|
||||
{{ $t('components.library.TrackDetail.userLibraryHeader') }}
|
||||
</h2>
|
||||
<library-widget
|
||||
:url="`tracks/${track.id}/libraries/`"
|
||||
@loaded="emit('libraries-loaded', $event)"
|
||||
>
|
||||
This track is present in the following libraries:
|
||||
{{ $t('components.library.TrackDetail.userLibraryDescription') }}
|
||||
</library-widget>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -47,19 +47,19 @@ fetchLicenses()
|
|||
<translate
|
||||
v-if="canEdit"
|
||||
>
|
||||
Edit this track
|
||||
{{ $t('components.library.TrackEdit.editTrackHeader') }}
|
||||
</translate>
|
||||
<translate
|
||||
key="2"
|
||||
>
|
||||
Suggest an edit on this track
|
||||
{{ $t('components.library.TrackEdit.suggestEditHeader') }}
|
||||
</translate>
|
||||
</h2>
|
||||
<div
|
||||
v-if="!object.is_local"
|
||||
class="ui message"
|
||||
>
|
||||
This object is managed by another server, you cannot edit it.
|
||||
{{ $t('components.library.TrackEdit.remoteObjectWarning') }}
|
||||
</div>
|
||||
<edit-form
|
||||
v-else-if="!isLoadingLicenses"
|
||||
|
|
|
@ -55,10 +55,10 @@ const { t } = useI18n()
|
|||
const router = useRouter()
|
||||
|
||||
const labels = computed(() => ({
|
||||
title: t('Radio Builder'),
|
||||
title: t('components.library.radios.Builder.title'),
|
||||
placeholder: {
|
||||
description: t('My awesome description'),
|
||||
name: t('My awesome radio')
|
||||
description: t('components.library.radios.Builder.descriptionPlaceholder'),
|
||||
name: t('components.library.radios.Builder.namePlaceholder')
|
||||
}
|
||||
}))
|
||||
|
||||
|
@ -203,10 +203,10 @@ onMounted(() => {
|
|||
<div>
|
||||
<section>
|
||||
<h2 class="ui header">
|
||||
Builder
|
||||
{{ $t('components.library.radios.Builder.builderHeader') }}
|
||||
</h2>
|
||||
<p>
|
||||
You can use this interface to build your own custom radio, which will play tracks according to your criteria.
|
||||
{{ $t('components.library.radios.Builder.builderDescription') }}
|
||||
</p>
|
||||
<div class="ui form">
|
||||
<div
|
||||
|
@ -215,16 +215,16 @@ onMounted(() => {
|
|||
>
|
||||
<h4 class="header">
|
||||
<template v-if="radioName">
|
||||
Radio updated
|
||||
{{ $t('components.library.radios.Builder.radioUpdateSuccess') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
Radio created
|
||||
{{ $t('components.library.radios.Builder.radioCreateSuccess') }}
|
||||
</template>
|
||||
</h4>
|
||||
</div>
|
||||
<div class="">
|
||||
<div class="field">
|
||||
<label for="name">Radio name</label>
|
||||
<label for="name">{{ $t('components.library.radios.Builder.radioNameLabel') }}</label>
|
||||
<input
|
||||
id="name"
|
||||
v-model="radioName"
|
||||
|
@ -234,7 +234,7 @@ onMounted(() => {
|
|||
>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="description">Description</label>
|
||||
<label for="description">{{ $t('components.library.radios.Builder.radioDescriptionLabel') }}</label>
|
||||
<textarea
|
||||
id="description"
|
||||
v-model="radioDesc"
|
||||
|
@ -249,7 +249,7 @@ onMounted(() => {
|
|||
v-model="isPublic"
|
||||
type="checkbox"
|
||||
>
|
||||
<label for="public">Display publicly</label>
|
||||
<label for="public">{{ $t('components.library.radios.Builder.publicLabel') }}</label>
|
||||
</div>
|
||||
<div class="ui hidden divider" />
|
||||
<button
|
||||
|
@ -257,7 +257,7 @@ onMounted(() => {
|
|||
:class="['ui', 'success', {loading: isLoading}, 'button']"
|
||||
@click="save"
|
||||
>
|
||||
Save
|
||||
{{ $t('components.library.radios.Builder.saveButton') }}
|
||||
</button>
|
||||
<radio-button
|
||||
v-if="id"
|
||||
|
@ -271,14 +271,14 @@ onMounted(() => {
|
|||
<label
|
||||
id="radioFilterLabel"
|
||||
for="radio-filters"
|
||||
>Add filters to customize your radio</label>
|
||||
>{{ $t('components.library.radios.Builder.addFiltersLabel') }}</label>
|
||||
<select
|
||||
id="radio-filters"
|
||||
v-model="currentFilterType"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option value="">
|
||||
Select a filter
|
||||
{{ $t('components.library.radios.Builder.selectFilterLabel') }}
|
||||
</option>
|
||||
<option
|
||||
v-for="f in availableFilters"
|
||||
|
@ -294,7 +294,7 @@ onMounted(() => {
|
|||
class="ui button"
|
||||
@click="add"
|
||||
>
|
||||
Add filter
|
||||
{{ $t('components.library.radios.Builder.addFilterButton') }}
|
||||
</button>
|
||||
</div>
|
||||
<p v-if="currentFilter">
|
||||
|
@ -305,19 +305,19 @@ onMounted(() => {
|
|||
<thead>
|
||||
<tr>
|
||||
<th class="two wide">
|
||||
Filter name
|
||||
{{ $t('components.library.radios.Builder.filterNameTableHeader') }}
|
||||
</th>
|
||||
<th class="one wide">
|
||||
Exclude
|
||||
{{ $t('components.library.radios.Builder.excludeTableHeader') }}
|
||||
</th>
|
||||
<th class="six wide">
|
||||
Config
|
||||
{{ $t('components.library.radios.Builder.configTableHeader') }}
|
||||
</th>
|
||||
<th class="five wide">
|
||||
Candidates
|
||||
{{ $t('components.library.radios.Builder.candidatesTableHeader') }}
|
||||
</th>
|
||||
<th class="two wide">
|
||||
Actions
|
||||
{{ $t('components.library.radios.Builder.actionsTableHeader') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -335,12 +335,9 @@ onMounted(() => {
|
|||
</table>
|
||||
<template v-if="checkResult && checkResult.candidates && checkResult.candidates.count">
|
||||
<h3
|
||||
v-translate="{count: checkResult.candidates.count}"
|
||||
class="ui header"
|
||||
:translate-n="checkResult.candidates.count"
|
||||
translate-plural="%{ count } tracks matching combined filters"
|
||||
>
|
||||
%{ count } track matching combined filters
|
||||
{{ $t('components.library.radios.Builder.matchingTracks', {count: checkResult.candidates.count}) }}
|
||||
</h3>
|
||||
<track-table
|
||||
v-if="checkResult.candidates.sample"
|
||||
|
|
|
@ -124,7 +124,7 @@ watch(exclude, fetchCandidates)
|
|||
for="exclude-filter"
|
||||
class="visually-hidden"
|
||||
>
|
||||
Exclude
|
||||
{{ $t('components.library.radios.Filter.excludeLabel') }}
|
||||
</label>
|
||||
</div>
|
||||
</td>
|
||||
|
@ -173,14 +173,14 @@ watch(exclude, fetchCandidates)
|
|||
:class="['ui', {'success': checkResult.candidates.count > 10}, 'label']"
|
||||
@click.prevent="showCandidadesModal = !showCandidadesModal"
|
||||
>
|
||||
{{ checkResult.candidates.count }} tracks matching filter
|
||||
{{ $t('components.library.radios.Filter.matchingTracks', {count: checkResult.candidates.count}) }}
|
||||
</a>
|
||||
<semantic-modal
|
||||
v-if="checkResult"
|
||||
v-model:show="showCandidadesModal"
|
||||
>
|
||||
<h4 class="header">
|
||||
Tracks matching filter
|
||||
{{ $t('components.library.radios.Filter.matchingTracksModalHeader') }}
|
||||
</h4>
|
||||
<div class="content">
|
||||
<div class="description">
|
||||
|
@ -192,7 +192,7 @@ watch(exclude, fetchCandidates)
|
|||
</div>
|
||||
<div class="actions">
|
||||
<button class="ui deny button">
|
||||
Cancel
|
||||
{{ $t('components.library.radios.Filter.cancelButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</semantic-modal>
|
||||
|
@ -202,7 +202,7 @@ watch(exclude, fetchCandidates)
|
|||
class="ui danger button"
|
||||
@click="$emit('delete', index)"
|
||||
>
|
||||
Remove
|
||||
{{ $t('components.library.radios.Filter.removeButton') }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -82,8 +82,8 @@ fetchData()
|
|||
const sharedLabels = useSharedLabels()
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
searchPlaceholder: t('Search by domain, name, account…'),
|
||||
openModeration: t('Open in moderation interface')
|
||||
searchPlaceholder: t('components.manage.ChannelsTable.searchPlaceholder'),
|
||||
openModeration: t('components.manage.ChannelsTable.openModeration')
|
||||
}))
|
||||
</script>
|
||||
|
||||
|
@ -92,7 +92,7 @@ const labels = computed(() => ({
|
|||
<div class="ui inline form">
|
||||
<div class="fields">
|
||||
<div class="ui six wide field">
|
||||
<label for="channel-search">Search</label>
|
||||
<label for="channel-search">{{ $t('components.manage.ChannelsTable.searchLabel') }}</label>
|
||||
<form @submit.prevent="query = search.value">
|
||||
<input
|
||||
id="channel-search"
|
||||
|
@ -105,7 +105,7 @@ const labels = computed(() => ({
|
|||
</form>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="channel-category">Category</label>
|
||||
<label for="channel-category">{{ $t('components.manage.ChannelsTable.categoryLabel') }}</label>
|
||||
<select
|
||||
id="channel-category"
|
||||
class="ui dropdown"
|
||||
|
@ -113,7 +113,7 @@ const labels = computed(() => ({
|
|||
@change="addSearchToken('category', ($event.target as HTMLSelectElement).value)"
|
||||
>
|
||||
<option value="">
|
||||
All
|
||||
{{ $t('components.manage.ChannelsTable.allOption') }}
|
||||
</option>
|
||||
<option value="podcast">
|
||||
{{ sharedLabels.fields.content_category.choices.podcast }}
|
||||
|
@ -127,7 +127,7 @@ const labels = computed(() => ({
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="channel-ordering">Ordering</label>
|
||||
<label for="channel-ordering">{{ $t('components.manage.ChannelsTable.orderingLabel') }}</label>
|
||||
<select
|
||||
id="channel-ordering"
|
||||
v-model="ordering"
|
||||
|
@ -143,17 +143,17 @@ const labels = computed(() => ({
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="channel-ordering-direction">Ordering direction</label>
|
||||
<label for="channel-ordering-direction">{{ $t('components.manage.ChannelsTable.orderingDirectionLabel') }}</label>
|
||||
<select
|
||||
id="channel-ordering-direction"
|
||||
v-model="orderingDirection"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option value="+">
|
||||
Ascending
|
||||
{{ $t('components.manage.ChannelsTable.ascendingOrdering') }}
|
||||
</option>
|
||||
<option value="-">
|
||||
Descending
|
||||
{{ $t('components.manage.ChannelsTable.descendingOrdering') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -176,22 +176,22 @@ const labels = computed(() => ({
|
|||
>
|
||||
<template #header-cells>
|
||||
<th>
|
||||
Name
|
||||
{{ $t('components.manage.ChannelsTable.nameTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Account
|
||||
{{ $t('components.manage.ChannelsTable.accountTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Domain
|
||||
{{ $t('components.manage.ChannelsTable.domainTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Albums
|
||||
{{ $t('components.manage.ChannelsTable.albumsTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Tracks
|
||||
{{ $t('components.manage.ChannelsTable.tracksTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Creation date
|
||||
{{ $t('components.manage.ChannelsTable.creationDateTableHeader') }}
|
||||
</th>
|
||||
</template>
|
||||
<template
|
||||
|
@ -232,7 +232,7 @@ const labels = computed(() => ({
|
|||
@click.prevent="addSearchToken('domain', scope.obj.attributed_to.domain)"
|
||||
>
|
||||
<i class="home icon" />
|
||||
Local
|
||||
{{ $t('components.manage.ChannelsTable.localLink') }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -257,12 +257,7 @@ const labels = computed(() => ({
|
|||
/>
|
||||
|
||||
<span v-if="result && result.results.length > 0">
|
||||
<translate
|
||||
|
||||
:translate-params="{start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}"
|
||||
>
|
||||
Showing results %{ start }-%{ end } on %{ total }
|
||||
</translate>
|
||||
{{ $t('components.manage.ChannelsTable.resultsDisplay', {start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -54,8 +54,8 @@ const actionFilters = computed(() => ({ q: query.value, ...props.filters }))
|
|||
const actions = computed(() => [
|
||||
{
|
||||
name: 'delete',
|
||||
label: t('Delete'),
|
||||
confirmationMessage: t('The selected albums will be removed, as well as associated tracks, uploads, favorites and listening history. This action is irreversible.'),
|
||||
label: t('components.manage.library.AlbumsTable.deleteActionLabel'),
|
||||
confirmationMessage: t('components.manage.library.AlbumsTable.deleteActionConfirmation'),
|
||||
isDangerous: true,
|
||||
allowAll: false,
|
||||
confirmColor: 'danger'
|
||||
|
@ -94,8 +94,8 @@ fetchData()
|
|||
|
||||
const sharedLabels = useSharedLabels()
|
||||
const labels = computed(() => ({
|
||||
searchPlaceholder: t('Search by domain, title, artist, MusicBrainz ID…'),
|
||||
openModeration: t('Open in moderation interface')
|
||||
searchPlaceholder: t('components.manage.library.AlbumsTable.searchPlaceholder'),
|
||||
openModeration: t('components.manage.library.AlbumsTable.openModeration')
|
||||
}))
|
||||
</script>
|
||||
|
||||
|
@ -104,7 +104,7 @@ const labels = computed(() => ({
|
|||
<div class="ui inline form">
|
||||
<div class="fields">
|
||||
<div class="ui six wide field">
|
||||
<label for="albums-search">Search</label>
|
||||
<label for="albums-search">{{ $t('components.manage.library.AlbumsTable.searchLabel') }}</label>
|
||||
<form @submit.prevent="query = search.value">
|
||||
<input
|
||||
id="albums-search"
|
||||
|
@ -117,7 +117,7 @@ const labels = computed(() => ({
|
|||
</form>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="albums-ordering">Ordering</label>
|
||||
<label for="albums-ordering">{{ $t('components.manage.library.AlbumsTable.orderingLabel') }}</label>
|
||||
<select
|
||||
id="albums-ordering"
|
||||
v-model="ordering"
|
||||
|
@ -133,16 +133,16 @@ const labels = computed(() => ({
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="albums-ordering-direction">Ordering direction</label>
|
||||
<label for="albums-ordering-direction">{{ $t('components.manage.library.AlbumsTable.orderingDirectionLabel') }}</label>
|
||||
<select
|
||||
v-model="orderingDirection"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option value="+">
|
||||
Ascending
|
||||
{{ $t('components.manage.library.AlbumsTable.ascendingOrdering') }}
|
||||
</option>
|
||||
<option value="-">
|
||||
Descending
|
||||
{{ $t('components.manage.library.AlbumsTable.descendingOrdering') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -165,22 +165,22 @@ const labels = computed(() => ({
|
|||
>
|
||||
<template #header-cells>
|
||||
<th>
|
||||
Title
|
||||
{{ $t('components.manage.library.AlbumsTable.nameTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Artist
|
||||
{{ $t('components.manage.library.AlbumsTable.artistTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Domain
|
||||
{{ $t('components.manage.library.AlbumsTable.domainTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Tracks
|
||||
{{ $t('components.manage.library.AlbumsTable.tracksTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Release date
|
||||
{{ $t('components.manage.library.AlbumsTable.releaseDateTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Creation date
|
||||
{{ $t('components.manage.library.AlbumsTable.creationDateTableHeader') }}
|
||||
</th>
|
||||
</template>
|
||||
<template
|
||||
|
@ -222,7 +222,7 @@ const labels = computed(() => ({
|
|||
@click.prevent="addSearchToken('domain', scope.obj.domain)"
|
||||
>
|
||||
<i class="home icon" />
|
||||
Local
|
||||
{{ $t('components.manage.library.AlbumsTable.localLink') }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -233,11 +233,11 @@ const labels = computed(() => ({
|
|||
v-if="scope.obj.release_date"
|
||||
:date="scope.obj.release_date"
|
||||
/>
|
||||
<translate
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
N/A
|
||||
</translate>
|
||||
{{ $t('components.manage.library.AlbumsTable.notApplicable') }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<human-date :date="scope.obj.creation_date" />
|
||||
|
@ -255,12 +255,7 @@ const labels = computed(() => ({
|
|||
/>
|
||||
|
||||
<span v-if="result && result.results.length > 0">
|
||||
<translate
|
||||
|
||||
:translate-params="{start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}"
|
||||
>
|
||||
Showing results %{ start }-%{ end } on %{ total }
|
||||
</translate>
|
||||
{{ $t('components.manage.library.AlbumsTable.resultsDisplay', {start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -52,8 +52,8 @@ const actionFilters = computed(() => ({ q: query.value, ...props.filters }))
|
|||
const actions = computed(() => [
|
||||
{
|
||||
name: 'delete',
|
||||
label: t('Delete'),
|
||||
confirmationMessage: t('The selected artist will be removed, as well as associated uploads, tracks, albums, favorites and listening history. This action is irreversible.'),
|
||||
label: t('components.manage.library.ArtistsTable.deleteActionLabel'),
|
||||
confirmationMessage: t('components.manage.library.ArtistsTable.deleteActionConfirmation'),
|
||||
isDangerous: true,
|
||||
allowAll: false,
|
||||
confirmColor: 'danger'
|
||||
|
@ -93,7 +93,7 @@ fetchData()
|
|||
const sharedLabels = useSharedLabels()
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
searchPlaceholder: t('Search by domain, name, MusicBrainz ID…')
|
||||
searchPlaceholder: t('components.manage.library.ArtistsTable.searchPlaceholder')
|
||||
}))
|
||||
|
||||
const getUrl = (artist: { channel?: number; id: number }) => {
|
||||
|
@ -108,7 +108,7 @@ const getUrl = (artist: { channel?: number; id: number }) => {
|
|||
<div class="ui inline form">
|
||||
<div class="fields">
|
||||
<div class="ui six wide field">
|
||||
<label for="artists-serarch">Search</label>
|
||||
<label for="artists-serarch">{{ $t('components.manage.library.ArtistsTable.searchLabel') }}</label>
|
||||
<form @submit.prevent="query = search.value">
|
||||
<input
|
||||
id="artists-search"
|
||||
|
@ -121,7 +121,7 @@ const getUrl = (artist: { channel?: number; id: number }) => {
|
|||
</form>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="artists-category">Category</label>
|
||||
<label for="artists-category">{{ $t('components.manage.library.ArtistsTable.categoryLabel') }}</label>
|
||||
<select
|
||||
id="artists-category"
|
||||
class="ui dropdown"
|
||||
|
@ -129,7 +129,7 @@ const getUrl = (artist: { channel?: number; id: number }) => {
|
|||
@change="addSearchToken('category', ($event.target as HTMLSelectElement).value)"
|
||||
>
|
||||
<option value="">
|
||||
All
|
||||
{{ $t('components.manage.library.ArtistsTable.allOption') }}
|
||||
</option>
|
||||
<option value="podcast">
|
||||
{{ sharedLabels.fields.content_category.choices.podcast }}
|
||||
|
@ -143,7 +143,7 @@ const getUrl = (artist: { channel?: number; id: number }) => {
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="artists-ordering">Ordering</label>
|
||||
<label for="artists-ordering">{{ $t('components.manage.library.ArtistsTable.orderingLabel') }}</label>
|
||||
<select
|
||||
id="artists-ordering"
|
||||
v-model="ordering"
|
||||
|
@ -159,17 +159,17 @@ const getUrl = (artist: { channel?: number; id: number }) => {
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="artists-ordering-direction">Ordering direction</label>
|
||||
<label for="artists-ordering-direction">{{ $t('components.manage.library.ArtistsTable.orderingDirectionLabel') }}</label>
|
||||
<select
|
||||
id="artists-ordering-direction"
|
||||
v-model="orderingDirection"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option value="+">
|
||||
Ascending
|
||||
{{ $t('components.manage.library.ArtistsTable.ascendingOrdering') }}
|
||||
</option>
|
||||
<option value="-">
|
||||
Descending
|
||||
{{ $t('components.manage.library.ArtistsTable.descendingOrdering') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -192,19 +192,19 @@ const getUrl = (artist: { channel?: number; id: number }) => {
|
|||
>
|
||||
<template #header-cells>
|
||||
<th>
|
||||
Name
|
||||
{{ $t('components.manage.library.ArtistsTable.nameTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Domain
|
||||
{{ $t('components.manage.library.ArtistsTable.domainTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Albums
|
||||
{{ $t('components.manage.library.ArtistsTable.albumsTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Tracks
|
||||
{{ $t('components.manage.library.ArtistsTable.tracksTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Creation date
|
||||
{{ $t('components.manage.library.ArtistsTable.creationDateTableHeader') }}
|
||||
</th>
|
||||
</template>
|
||||
<template
|
||||
|
@ -234,7 +234,7 @@ const getUrl = (artist: { channel?: number; id: number }) => {
|
|||
@click.prevent="addSearchToken('domain', scope.obj.domain)"
|
||||
>
|
||||
<i class="home icon" />
|
||||
Local
|
||||
{{ $t('components.manage.library.ArtistsTable.localLink') }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -259,12 +259,7 @@ const getUrl = (artist: { channel?: number; id: number }) => {
|
|||
/>
|
||||
|
||||
<span v-if="result && result.results.length > 0">
|
||||
<translate
|
||||
|
||||
:translate-params="{start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}"
|
||||
>
|
||||
Showing results %{ start }-%{ end } on %{ total }
|
||||
</translate>
|
||||
{{ $t('components.manage.library.ArtistsTable.resultsDisplay', {start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -142,7 +142,7 @@ fetchData()
|
|||
const { t } = useI18n()
|
||||
const sharedLabels = useSharedLabels()
|
||||
const labels = computed(() => ({
|
||||
searchPlaceholder: t('Search by account, summary, domain…')
|
||||
searchPlaceholder: t('components.manage.library.EditsCardList.searchPlaceholder')
|
||||
}))
|
||||
|
||||
const handle = (type: 'delete' | 'approved', id: string, value: boolean) => {
|
||||
|
@ -165,7 +165,7 @@ const getCurrentState = (target?: StateTarget): ReviewState => {
|
|||
<div class="ui inline form">
|
||||
<div class="fields">
|
||||
<div class="ui field">
|
||||
<label for="search-edits">Search</label>
|
||||
<label for="search-edits">{{ $t('components.manage.library.EditsCardList.searchPlaceholder') }}</label>
|
||||
<form @submit.prevent="query = search.value">
|
||||
<input
|
||||
id="search-edits"
|
||||
|
@ -178,7 +178,7 @@ const getCurrentState = (target?: StateTarget): ReviewState => {
|
|||
</form>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="edit-status">Status</label>
|
||||
<label for="edit-status">{{ $t('components.manage.library.EditsCardList.statusLabel') }}</label>
|
||||
<select
|
||||
id="edit-status"
|
||||
class="ui dropdown"
|
||||
|
@ -186,21 +186,21 @@ const getCurrentState = (target?: StateTarget): ReviewState => {
|
|||
@change="addSearchToken('is_approved', ($event.target as HTMLSelectElement).value)"
|
||||
>
|
||||
<option value="">
|
||||
All
|
||||
{{ $t('components.manage.library.EditsCardList.allOption') }}
|
||||
</option>
|
||||
<option value="null">
|
||||
Pending review
|
||||
{{ $t('components.manage.library.EditsCardList.pendingReviewLabel') }}
|
||||
</option>
|
||||
<option value="yes">
|
||||
Approved
|
||||
{{ $t('components.manage.library.EditsCardList.approvedLabel') }}
|
||||
</option>
|
||||
<option value="no">
|
||||
Rejected
|
||||
{{ $t('components.manage.library.EditsCardList.rejectedLabel') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="edit-ordering">Ordering</label>
|
||||
<label for="edit-ordering">{{ $t('components.manage.library.EditsCardList.orderingLabel') }}</label>
|
||||
<select
|
||||
id="edit-ordering"
|
||||
v-model="ordering"
|
||||
|
@ -216,17 +216,17 @@ const getCurrentState = (target?: StateTarget): ReviewState => {
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="edit-ordering-direction">Order</label>
|
||||
<label for="edit-ordering-direction">{{ $t('components.manage.library.EditsCardList.orderingDirectionLabel') }}</label>
|
||||
<select
|
||||
id="edit-ordering-direction"
|
||||
v-model="orderingDirection"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option value="+">
|
||||
Ascending
|
||||
{{ $t('components.manage.library.EditsCardList.ascendingOrdering') }}
|
||||
</option>
|
||||
<option value="-">
|
||||
Descending
|
||||
{{ $t('components.manage.library.EditsCardList.descendingOrdering') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -266,12 +266,7 @@ const getCurrentState = (target?: StateTarget): ReviewState => {
|
|||
/>
|
||||
|
||||
<span v-if="result && result.results.length > 0">
|
||||
<translate
|
||||
|
||||
:translate-params="{start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}"
|
||||
>
|
||||
Showing results %{ start }-%{ end } on %{ total }
|
||||
</translate>
|
||||
{{ $t('components.manage.library.EditsCardList.resultsDisplay', {start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -54,8 +54,8 @@ const actionFilters = computed(() => ({ q: query.value, ...props.filters }))
|
|||
const actions = computed(() => [
|
||||
{
|
||||
name: 'delete',
|
||||
label: t('Delete'),
|
||||
confirmationMessage: t('The selected library will be removed, as well as associated uploads and follows. This action is irreversible.'),
|
||||
label: t('components.manage.library.LibrariesTable.deleteActionLabel'),
|
||||
confirmationMessage: t('components.manage.library.LibrariesTable.deleteActionConfirmation'),
|
||||
isDangerous: true,
|
||||
allowAll: false,
|
||||
confirmColor: 'danger'
|
||||
|
@ -94,7 +94,7 @@ fetchData()
|
|||
|
||||
const sharedLabels = useSharedLabels()
|
||||
const labels = computed(() => ({
|
||||
searchPlaceholder: t('Search by domain, actor, name, description…')
|
||||
searchPlaceholder: t('components.manage.library.LibrariesTable.searchPlaceholder')
|
||||
}))
|
||||
|
||||
const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
||||
|
@ -107,7 +107,7 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
<div class="ui inline form">
|
||||
<div class="fields">
|
||||
<div class="ui six wide field">
|
||||
<label for="libraries-search">Search</label>
|
||||
<label for="libraries-search">{{ $t('components.manage.library.LibrariesTable.searchLabel') }}</label>
|
||||
<form @submit.prevent="query = search.value">
|
||||
<input
|
||||
id="libraries-search"
|
||||
|
@ -120,7 +120,7 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
</form>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="libraries-visibility">Visibility</label>
|
||||
<label for="libraries-visibility">{{ $t('components.manage.library.LibrariesTable.visibilityLabel') }}</label>
|
||||
<select
|
||||
id="libraries-visibility"
|
||||
class="ui dropdown"
|
||||
|
@ -128,7 +128,7 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
@change="addSearchToken('privacy_level', ($event.target as HTMLSelectElement).value)"
|
||||
>
|
||||
<option value="">
|
||||
All
|
||||
{{ $t('components.manage.library.LibrariesTable.allOption') }}
|
||||
</option>
|
||||
<option value="me">
|
||||
{{ sharedLabels.fields.privacy_level.shortChoices.me }}
|
||||
|
@ -142,7 +142,7 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="libraries-ordering">Ordering</label>
|
||||
<label for="libraries-ordering">{{ $t('components.manage.library.LibrariesTable.orderingLabel') }}</label>
|
||||
<select
|
||||
id="libraries-ordering"
|
||||
v-model="ordering"
|
||||
|
@ -158,17 +158,17 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="libraries-ordering-direction">Ordering direction</label>
|
||||
<label for="libraries-ordering-direction">{{ $t('components.manage.library.LibrariesTable.orderingDirectionLabel') }}</label>
|
||||
<select
|
||||
id="libraries-ordering-direction"
|
||||
v-model="orderingDirection"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option value="+">
|
||||
Ascending
|
||||
{{ $t('components.manage.library.LibrariesTable.ascendingOrdering') }}
|
||||
</option>
|
||||
<option value="-">
|
||||
Descending
|
||||
{{ $t('components.manage.library.LibrariesTable.descendingOrdering') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -191,25 +191,25 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
>
|
||||
<template #header-cells>
|
||||
<th>
|
||||
Name
|
||||
{{ $t('components.manage.library.LibrariesTable.nameTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Account
|
||||
{{ $t('components.manage.library.LibrariesTable.accountTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Domain
|
||||
{{ $t('components.manage.library.LibrariesTable.domainTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Visibility
|
||||
{{ $t('components.manage.library.LibrariesTable.visibilityTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Uploads
|
||||
{{ $t('components.manage.library.LibrariesTable.uploadsTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Followers
|
||||
{{ $t('components.manage.library.LibrariesTable.followersTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Creation date
|
||||
{{ $t('components.manage.library.LibrariesTable.creationDateTableHeader') }}
|
||||
</th>
|
||||
</template>
|
||||
<template #row-cells="scope">
|
||||
|
@ -248,7 +248,7 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
@click.prevent="addSearchToken('domain', scope.obj.domain)"
|
||||
>
|
||||
<i class="home icon" />
|
||||
Local
|
||||
{{ $t('components.manage.library.LibrariesTable.localLink') }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -283,12 +283,7 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
/>
|
||||
|
||||
<span v-if="result && result.results.length > 0">
|
||||
<translate
|
||||
|
||||
:translate-params="{start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}"
|
||||
>
|
||||
Showing results %{ start }-%{ end } on %{ total }
|
||||
</translate>
|
||||
{{ $t('components.manage.library.LibrariesTable.resultsDisplay', {start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -57,8 +57,8 @@ const actionFilters = computed(() => ({ q: query.value, ...props.filters }))
|
|||
const actions = computed(() => [
|
||||
{
|
||||
name: 'delete',
|
||||
label: t('Delete'),
|
||||
confirmationMessage: t('The selected tag will be removed and unlinked with existing content, if any. This action is irreversible.'),
|
||||
label: t('components.manage.library.TagsTable.deleteActionLabel'),
|
||||
confirmationMessage: t('components.manage.library.TagsTable.deleteActionConfirmation'),
|
||||
isDangerous: true,
|
||||
allowAll: false,
|
||||
confirmColor: 'danger'
|
||||
|
@ -97,7 +97,7 @@ fetchData()
|
|||
|
||||
const sharedLabels = useSharedLabels()
|
||||
const labels = computed(() => ({
|
||||
searchPlaceholder: t('Search by name')
|
||||
searchPlaceholder: t('components.manage.library.TagsTable.searchPlaceholder')
|
||||
}))
|
||||
|
||||
const detailedUpload = ref()
|
||||
|
@ -109,7 +109,7 @@ const showUploadDetailModal = ref(false)
|
|||
<div class="ui inline form">
|
||||
<div class="fields">
|
||||
<div class="ui six wide field">
|
||||
<label for="tags-search">Search</label>
|
||||
<label for="tags-search">{{ $t('components.manage.library.TagsTable.searchLabel') }}</label>
|
||||
<form @submit.prevent="query = search.value">
|
||||
<input
|
||||
id="tags-search"
|
||||
|
@ -122,7 +122,7 @@ const showUploadDetailModal = ref(false)
|
|||
</form>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="tags-ordering">Ordering</label>
|
||||
<label for="tags-ordering">{{ $t('components.manage.library.TagsTable.orderingLabel') }}</label>
|
||||
<select
|
||||
id="tags-ordering"
|
||||
v-model="ordering"
|
||||
|
@ -138,17 +138,17 @@ const showUploadDetailModal = ref(false)
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="tags-ordering-direction">Ordering direction</label>
|
||||
<label for="tags-ordering-direction">{{ $t('components.manage.library.TagsTable.orderingDirectionLabel') }}</label>
|
||||
<select
|
||||
id="tags-ordering-direction"
|
||||
v-model="orderingDirection"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option value="+">
|
||||
Ascending
|
||||
{{ $t('components.manage.library.TagsTable.ascendingOrdering') }}
|
||||
</option>
|
||||
<option value="-">
|
||||
Descending
|
||||
{{ $t('components.manage.library.TagsTable.descendingOrdering') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -177,19 +177,19 @@ const showUploadDetailModal = ref(false)
|
|||
>
|
||||
<template #header-cells>
|
||||
<th>
|
||||
Name
|
||||
{{ $t('components.manage.library.TagsTable.nameTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Artists
|
||||
{{ $t('components.manage.library.TagsTable.artistsTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Albums
|
||||
{{ $t('components.manage.library.TagsTable.albumsTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Tracks
|
||||
{{ $t('components.manage.library.TagsTable.tracksTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Creation date
|
||||
{{ $t('components.manage.library.TagsTable.creationDateTableHeader') }}
|
||||
</th>
|
||||
</template>
|
||||
<template
|
||||
|
@ -225,12 +225,7 @@ const showUploadDetailModal = ref(false)
|
|||
/>
|
||||
|
||||
<span v-if="result && result.results.length > 0">
|
||||
<translate
|
||||
|
||||
:translate-params="{start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}"
|
||||
>
|
||||
Showing results %{ start }-%{ end } on %{ total }
|
||||
</translate>
|
||||
{{ $t('components.manage.library.TagsTable.resultsDisplay', {start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -52,8 +52,8 @@ const actionFilters = computed(() => ({ q: query.value, ...props.filters }))
|
|||
const actions = computed(() => [
|
||||
{
|
||||
name: 'delete',
|
||||
label: t('Delete'),
|
||||
confirmationMessage: t('The selected tracks will be removed, as well as associated uploads, favorites and listening history. This action is irreversible.'),
|
||||
label: t('components.manage.library.TracksTable.deleteActionLabel'),
|
||||
confirmationMessage: t('components.manage.library.TracksTable.deleteActionConfirmation'),
|
||||
isDangerous: true,
|
||||
allowAll: false,
|
||||
confirmColor: 'danger'
|
||||
|
@ -92,7 +92,7 @@ fetchData()
|
|||
|
||||
const sharedLabels = useSharedLabels()
|
||||
const labels = computed(() => ({
|
||||
searchPlaceholder: t('Search by domain, title, artist, album, MusicBrainz ID…')
|
||||
searchPlaceholder: t('components.manage.library.TracksTable.searchPlaceholder')
|
||||
}))
|
||||
</script>
|
||||
|
||||
|
@ -101,7 +101,7 @@ const labels = computed(() => ({
|
|||
<div class="ui inline form">
|
||||
<div class="fields">
|
||||
<div class="ui six wide field">
|
||||
<label for="tracks-search">Search</label>
|
||||
<label for="tracks-search">{{ $t('components.manage.library.TracksTable.searchLabel') }}</label>
|
||||
<form @submit.prevent="query = search.value">
|
||||
<input
|
||||
id="tracks-search"
|
||||
|
@ -114,7 +114,7 @@ const labels = computed(() => ({
|
|||
</form>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="tracks-ordering">Ordering</label>
|
||||
<label for="tracks-ordering">{{ $t('components.manage.library.TracksTable.orderingLabel') }}</label>
|
||||
<select
|
||||
id="tracks-ordering"
|
||||
v-model="ordering"
|
||||
|
@ -130,17 +130,17 @@ const labels = computed(() => ({
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="tracks-ordering-direction">Ordering direction</label>
|
||||
<label for="tracks-ordering-direction">{{ $t('components.manage.library.TracksTable.orderingDirectionLabel') }}</label>
|
||||
<select
|
||||
id="tracks-ordering-direction"
|
||||
v-model="orderingDirection"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option value="+">
|
||||
Ascending
|
||||
{{ $t('components.manage.library.TracksTable.ascendingOrdering') }}
|
||||
</option>
|
||||
<option value="-">
|
||||
Descending
|
||||
{{ $t('components.manage.library.TracksTable.descendingOrdering') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -163,22 +163,22 @@ const labels = computed(() => ({
|
|||
>
|
||||
<template #header-cells>
|
||||
<th>
|
||||
Title
|
||||
{{ $t('components.manage.library.TracksTable.titleTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Album
|
||||
{{ $t('components.manage.library.TracksTable.albumTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Artist
|
||||
{{ $t('components.manage.library.TracksTable.artistTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Domain
|
||||
{{ $t('components.manage.library.TracksTable.domainTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
License
|
||||
{{ $t('components.manage.library.TracksTable.licenseTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Creation date
|
||||
{{ $t('components.manage.library.TracksTable.creationDateTableHeader') }}
|
||||
</th>
|
||||
</template>
|
||||
<template
|
||||
|
@ -232,7 +232,7 @@ const labels = computed(() => ({
|
|||
@click.prevent="addSearchToken('domain', scope.obj.domain)"
|
||||
>
|
||||
<i class="home icon" />
|
||||
Local
|
||||
{{ $t('components.manage.library.TracksTable.localLink') }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -243,11 +243,11 @@ const labels = computed(() => ({
|
|||
:title="scope.obj.license"
|
||||
@click.prevent="addSearchToken('license', scope.obj.license)"
|
||||
>{{ scope.obj.license }}</a>
|
||||
<translate
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
N/A
|
||||
</translate>
|
||||
{{ $t('components.manage.library.TracksTable.notApplicable') }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<human-date :date="scope.obj.creation_date" />
|
||||
|
@ -265,12 +265,7 @@ const labels = computed(() => ({
|
|||
/>
|
||||
|
||||
<span v-if="result && result.results.length > 0">
|
||||
<translate
|
||||
|
||||
:translate-params="{start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}"
|
||||
>
|
||||
Showing results %{ start }-%{ end } on %{ total }
|
||||
</translate>
|
||||
{{ $t('components.manage.library.TracksTable.resultsDisplay', {start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -59,8 +59,8 @@ const actionFilters = computed(() => ({ q: query.value, ...props.filters }))
|
|||
const actions = computed(() => [
|
||||
{
|
||||
name: 'delete',
|
||||
label: t('Delete'),
|
||||
confirmationMessage: t('The selected upload will be removed. This action is irreversible.'),
|
||||
label: t('components.manage.library.UploadsTable.deleteActionLabel'),
|
||||
confirmationMessage: t('components.manage.library.UploadsTable.deleteActionConfirmation'),
|
||||
isDangerous: true,
|
||||
allowAll: false,
|
||||
confirmColor: 'danger'
|
||||
|
@ -99,7 +99,7 @@ fetchData()
|
|||
|
||||
const sharedLabels = useSharedLabels()
|
||||
const labels = computed(() => ({
|
||||
searchPlaceholder: t('Search by domain, actor, name, reference, source…')
|
||||
searchPlaceholder: t('components.manage.library.UploadsTable.searchPlaceholder')
|
||||
}))
|
||||
|
||||
const displayName = (upload: Upload): string => {
|
||||
|
@ -123,7 +123,7 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
<div class="ui inline form">
|
||||
<div class="fields">
|
||||
<div class="ui six wide field">
|
||||
<label for="uploads-search">Search</label>
|
||||
<label for="uploads-search">{{ $t('components.manage.library.UploadsTable.searchLabel') }}</label>
|
||||
<form @submit.prevent="query = search.value">
|
||||
<input
|
||||
id="uploads-search"
|
||||
|
@ -136,7 +136,7 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
</form>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="uploads-visibility">Visibility</label>
|
||||
<label for="uploads-visibility">{{ $t('components.manage.library.UploadsTable.visibilityLabel') }}</label>
|
||||
<select
|
||||
id="uploads-visibility"
|
||||
class="ui dropdown"
|
||||
|
@ -144,7 +144,7 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
@change="addSearchToken('privacy_level', ($event.target as HTMLSelectElement).value)"
|
||||
>
|
||||
<option value="">
|
||||
All
|
||||
{{ $t('components.manage.library.UploadsTable.allOption') }}
|
||||
</option>
|
||||
<option value="me">
|
||||
{{ sharedLabels.fields.privacy_level.shortChoices.me }}
|
||||
|
@ -158,7 +158,7 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="uploads-status">Import status</label>
|
||||
<label for="uploads-status">{{ $t('components.manage.library.UploadsTable.importStatusLabel') }}</label>
|
||||
<select
|
||||
id="uploads-status"
|
||||
class="ui dropdown"
|
||||
|
@ -166,24 +166,24 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
@change="addSearchToken('status', ($event.target as HTMLSelectElement).value)"
|
||||
>
|
||||
<option value="">
|
||||
All
|
||||
{{ $t('components.manage.library.UploadsTable.allOption') }}
|
||||
</option>
|
||||
<option value="pending">
|
||||
Pending
|
||||
{{ $t('components.manage.library.UploadsTable.pendingStatus') }}
|
||||
</option>
|
||||
<option value="skipped">
|
||||
Skipped
|
||||
{{ $t('components.manage.library.UploadsTable.skippedStatus') }}
|
||||
</option>
|
||||
<option value="errored">
|
||||
Failed
|
||||
{{ $t('components.manage.library.UploadsTable.failedStatus') }}
|
||||
</option>
|
||||
<option value="finished">
|
||||
Finished
|
||||
{{ $t('components.manage.library.UploadsTable.finishedStatus') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="uploads-ordering">Ordering</label>
|
||||
<label for="uploads-ordering">{{ $t('components.manage.library.UploadsTable.orderingLabel') }}</label>
|
||||
<select
|
||||
id="uploads-ordering"
|
||||
v-model="ordering"
|
||||
|
@ -199,17 +199,17 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="uploads-ordering-direction">Ordering direction</label>
|
||||
<label for="uploads-ordering-direction">{{ $t('components.manage.library.UploadsTable.orderingDirectionLabel') }}</label>
|
||||
<select
|
||||
id="uploads-ordering-direction"
|
||||
v-model="orderingDirection"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option value="+">
|
||||
Ascending
|
||||
{{ $t('components.manage.library.UploadsTable.ascendingOrdering') }}
|
||||
</option>
|
||||
<option value="-">
|
||||
Descending
|
||||
{{ $t('components.manage.library.UploadsTable.descendingOrdering') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -238,31 +238,31 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
>
|
||||
<template #header-cells>
|
||||
<th>
|
||||
Name
|
||||
{{ $t('components.manage.library.UploadsTable.nameTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Library
|
||||
{{ $t('components.manage.library.UploadsTable.libraryTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Account
|
||||
{{ $t('components.manage.library.UploadsTable.accountTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Domain
|
||||
{{ $t('components.manage.library.UploadsTable.domainTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Visibility
|
||||
{{ $t('components.manage.library.UploadsTable.visibilityTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Import status
|
||||
{{ $t('components.manage.library.UploadsTable.importStatusTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Size
|
||||
{{ $t('components.manage.library.UploadsTable.sizeTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Creation date
|
||||
{{ $t('components.manage.library.UploadsTable.creationDateTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Accessed date
|
||||
{{ $t('components.manage.library.UploadsTable.creationDateTableHeader') }}
|
||||
</th>
|
||||
</template>
|
||||
<template #row-cells="scope">
|
||||
|
@ -312,7 +312,7 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
@click.prevent="addSearchToken('domain', scope.obj.domain)"
|
||||
>
|
||||
<i class="home icon" />
|
||||
Local
|
||||
{{ $t('components.manage.library.UploadsTable.localLink') }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -347,7 +347,7 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
<translate
|
||||
v-else
|
||||
>
|
||||
N/A
|
||||
{{ $t('components.manage.library.UploadsTable.notApplicable') }}
|
||||
</translate>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -361,7 +361,7 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
<translate
|
||||
v-else
|
||||
>
|
||||
N/A
|
||||
{{ $t('components.manage.library.UploadsTable.notApplicable') }}
|
||||
</translate>
|
||||
</td>
|
||||
</template>
|
||||
|
@ -377,12 +377,7 @@ const getPrivacyLevelChoice = (privacyLevel: PrivacyLevel) => {
|
|||
/>
|
||||
|
||||
<span v-if="result && result.results.length > 0">
|
||||
<translate
|
||||
|
||||
:translate-params="{start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}"
|
||||
>
|
||||
Showing results %{ start }-%{ end } on %{ total }
|
||||
</translate>
|
||||
{{ $t('components.manage.library.UploadsTable.resultsDisplay', {start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -56,7 +56,7 @@ const actionFilters = computed(() => ({ q: query.value, ...props.filters }))
|
|||
const actions = computed(() => [
|
||||
{
|
||||
name: 'purge',
|
||||
label: t('Purge'),
|
||||
label: t('components.manage.moderation.AccountsTable.purgeLabel'),
|
||||
isDangerous: true
|
||||
}
|
||||
])
|
||||
|
@ -93,7 +93,7 @@ fetchData()
|
|||
|
||||
const sharedLabels = useSharedLabels()
|
||||
const labels = computed(() => ({
|
||||
searchPlaceholder: t('Search by domain, username, bio…')
|
||||
searchPlaceholder: t('components.manage.moderation.AccountsTable.searchPlaceholder')
|
||||
}))
|
||||
</script>
|
||||
|
||||
|
@ -102,7 +102,7 @@ const labels = computed(() => ({
|
|||
<div class="ui inline form">
|
||||
<div class="fields">
|
||||
<div class="ui six wide field">
|
||||
<label for="accounts-search">Search</label>
|
||||
<label for="accounts-search">{{ $t('components.manage.moderation.AccountsTable.searchLabel') }}</label>
|
||||
<form @submit.prevent="query = search.value">
|
||||
<input
|
||||
id="accounts-search"
|
||||
|
@ -115,7 +115,7 @@ const labels = computed(() => ({
|
|||
</form>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="accounts-ordering">Ordering</label>
|
||||
<label for="accounts-ordering">{{ $t('components.manage.moderation.AccountsTable.orderingLabel') }}</label>
|
||||
<select
|
||||
id="accounts-ordering"
|
||||
v-model="ordering"
|
||||
|
@ -131,17 +131,17 @@ const labels = computed(() => ({
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="accounts-ordering-direction">Ordering direction</label>
|
||||
<label for="accounts-ordering-direction">{{ $t('components.manage.moderation.AccountsTable.orderingDirectionLabel') }}</label>
|
||||
<select
|
||||
id="accounts-ordering-direction"
|
||||
v-model="orderingDirection"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option value="+">
|
||||
Ascending
|
||||
{{ $t('components.manage.moderation.AccountsTable.ascendingOrdering') }}
|
||||
</option>
|
||||
<option value="-">
|
||||
Descending
|
||||
{{ $t('components.manage.moderation.AccountsTable.descendingOrdering') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -164,22 +164,22 @@ const labels = computed(() => ({
|
|||
>
|
||||
<template #header-cells>
|
||||
<th>
|
||||
Name
|
||||
{{ $t('components.manage.moderation.AccountsTable.nameTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Domain
|
||||
{{ $t('components.manage.moderation.AccountsTable.domainTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Uploads
|
||||
{{ $t('components.manage.moderation.AccountsTable.uploadsTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
First seen
|
||||
{{ $t('components.manage.moderation.AccountsTable.firstSeenTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Last seen
|
||||
{{ $t('components.manage.moderation.AccountsTable.lastSeenTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Under moderation rule
|
||||
{{ $t('components.manage.moderation.AccountsTable.moderationRuleTableHeader') }}
|
||||
</th>
|
||||
</template>
|
||||
<template
|
||||
|
@ -209,7 +209,7 @@ const labels = computed(() => ({
|
|||
@click.prevent="addSearchToken('domain', scope.obj.domain)"
|
||||
>
|
||||
<i class="home icon" />
|
||||
Local account
|
||||
{{ $t('components.manage.moderation.AccountsTable.localLink') }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -225,7 +225,7 @@ const labels = computed(() => ({
|
|||
/>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="scope.obj.instance_policy"><i class="shield icon" /> Yes</span>
|
||||
<span v-if="scope.obj.instance_policy"><i class="shield icon" />{{ $t('components.manage.moderation.AccountsTable.moderationRuleStatus') }}</span>
|
||||
</td>
|
||||
</template>
|
||||
</action-table>
|
||||
|
@ -240,12 +240,7 @@ const labels = computed(() => ({
|
|||
/>
|
||||
|
||||
<span v-if="result && result.results.length > 0">
|
||||
<translate
|
||||
|
||||
:translate-params="{start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}"
|
||||
>
|
||||
Showing results %{ start }-%{ end } on %{ total }
|
||||
</translate>
|
||||
{{ $t('components.manage.moderation.AccountsTable.resultsDisplay', {start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -50,19 +50,19 @@ const actionFilters = computed(() => ({ q: query.value, ...props.filters }))
|
|||
const actions = computed(() => [
|
||||
{
|
||||
name: 'purge',
|
||||
label: t('Purge'),
|
||||
label: t('components.manage.moderation.DomainsTable.purgeLabel'),
|
||||
isDangerous: true
|
||||
},
|
||||
{
|
||||
name: 'allow_list_add',
|
||||
label: t('Add to allow-list'),
|
||||
label: t('components.manage.moderation.DomainsTable.allowListAddLabel'),
|
||||
filterCheckable: (obj: { allowed: boolean }) => {
|
||||
return !obj.allowed
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'allow_list_remove',
|
||||
label: t('Remove from allow-list'),
|
||||
label: t('components.manage.moderation.DomainsTable.allowListRemoveLabel'),
|
||||
filterCheckable: (obj: { allowed: boolean }) => {
|
||||
return obj.allowed
|
||||
}
|
||||
|
@ -108,8 +108,8 @@ fetchData()
|
|||
|
||||
const sharedLabels = useSharedLabels()
|
||||
const labels = computed(() => ({
|
||||
searchPlaceholder: t('Search by name…'),
|
||||
allowListTitle: t('This domain is present in your allow-list')
|
||||
searchPlaceholder: t('components.manage.moderation.DomainsTable.searchPlaceholder'),
|
||||
allowListTitle: t('components.manage.moderation.DomainsTable.allowListTitle')
|
||||
}))
|
||||
</script>
|
||||
|
||||
|
@ -118,7 +118,7 @@ const labels = computed(() => ({
|
|||
<div class="ui inline form">
|
||||
<div class="fields">
|
||||
<div class="ui field">
|
||||
<label for="domains-search">Search</label>
|
||||
<label for="domains-search">{{ $t('components.manage.moderation.DomainsTable.searchLabel') }}</label>
|
||||
<input
|
||||
id="domains-search"
|
||||
v-model="query"
|
||||
|
@ -131,25 +131,25 @@ const labels = computed(() => ({
|
|||
v-if="allowListEnabled"
|
||||
class="field"
|
||||
>
|
||||
<label for="domains-allow-list">Is present on allow-list</label>
|
||||
<label for="domains-allow-list">{{ $t('components.manage.moderation.DomainsTable.inAllowListLabel') }}</label>
|
||||
<select
|
||||
id="domains-allow-list"
|
||||
v-model="allowed"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option :value="null">
|
||||
All
|
||||
{{ $t('components.manage.moderation.DomainsTable.allOption') }}
|
||||
</option>
|
||||
<option :value="true">
|
||||
Yes
|
||||
{{ $t('components.manage.moderation.DomainsTable.positiveOption') }}
|
||||
</option>
|
||||
<option :value="false">
|
||||
No
|
||||
{{ $t('components.manage.moderation.DomainsTable.negativeOption') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="domains-ordering">Ordering</label>
|
||||
<label for="domains-ordering">{{ $t('components.manage.moderation.DomainsTable.orderingLabel') }}</label>
|
||||
<select
|
||||
id="domains-ordering"
|
||||
v-model="ordering"
|
||||
|
@ -165,17 +165,17 @@ const labels = computed(() => ({
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="domains-ordering-direction">Ordering direction</label>
|
||||
<label for="domains-ordering-direction">{{ $t('components.manage.moderation.DomainsTable.orderingDirectionLabel') }}</label>
|
||||
<select
|
||||
id="domains-ordering-direction"
|
||||
v-model="orderingDirection"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option value="+">
|
||||
Ascending
|
||||
{{ $t('components.manage.moderation.DomainsTable.ascendingOrdering') }}
|
||||
</option>
|
||||
<option value="-">
|
||||
Descending
|
||||
{{ $t('components.manage.moderation.DomainsTable.descendingOrdering') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -199,19 +199,19 @@ const labels = computed(() => ({
|
|||
>
|
||||
<template #header-cells>
|
||||
<th>
|
||||
Name
|
||||
{{ $t('components.manage.moderation.DomainsTable.nameTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Users
|
||||
{{ $t('components.manage.moderation.DomainsTable.usersTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Received messages
|
||||
{{ $t('components.manage.moderation.DomainsTable.receivedMessagesTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
First seen
|
||||
{{ $t('components.manage.moderation.DomainsTable.firstSeenTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Under moderation rule
|
||||
{{ $t('components.manage.moderation.DomainsTable.moderationRuleTableHeader') }}
|
||||
</th>
|
||||
</template>
|
||||
<template
|
||||
|
@ -237,7 +237,7 @@ const labels = computed(() => ({
|
|||
<human-date :date="scope.obj.creation_date" />
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="scope.obj.instance_policy"><i class="shield icon" /> Yes</span>
|
||||
<span v-if="scope.obj.instance_policy"><i class="shield icon" />{{ $t('components.manage.moderation.DomainsTable.moderationRuleStatus') }}</span>
|
||||
</td>
|
||||
</template>
|
||||
</action-table>
|
||||
|
@ -247,7 +247,7 @@ const labels = computed(() => ({
|
|||
>
|
||||
<div class="ui icon header">
|
||||
<i class="server icon" />
|
||||
No other pods found
|
||||
{{ $t('components.manage.moderation.DomainsTable.emptyState') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -261,12 +261,7 @@ const labels = computed(() => ({
|
|||
/>
|
||||
|
||||
<span v-if="result && result.results.length > 0">
|
||||
<translate
|
||||
|
||||
:translate-params="{start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}"
|
||||
>
|
||||
Showing results %{ start }-%{ end } on %{ total }
|
||||
</translate>
|
||||
{{ $t('components.manage.moderation.DomainsTable.resultsDisplay', {start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -25,18 +25,18 @@ const summary = useMarkdown(() => props.object.summary)
|
|||
<i class="user icon" />{{ object.actor }}
|
||||
<template v-if="object.is_active">
|
||||
<i class="play icon" />
|
||||
Enabled
|
||||
{{ $t('components.manage.moderation.InstancePolicyCard.enabledStatus') }}
|
||||
</template>
|
||||
<template v-if="!object.is_active">
|
||||
<i class="pause icon" />
|
||||
Paused
|
||||
{{ $t('components.manage.moderation.InstancePolicyCard.pausedStatus') }}
|
||||
</template>
|
||||
</p>
|
||||
<div>
|
||||
<p><strong>Rule</strong></p>
|
||||
<p><strong>{{ $t('components.manage.moderation.InstancePolicyCard.ruleHeader') }}</strong></p>
|
||||
<p v-if="object.block_all">
|
||||
<i class="ban icon" />
|
||||
Block everything
|
||||
{{ $t('components.manage.moderation.InstancePolicyCard.blockAllRule') }}
|
||||
</p>
|
||||
<div
|
||||
v-else
|
||||
|
@ -48,7 +48,7 @@ const summary = useMarkdown(() => props.object.summary)
|
|||
>
|
||||
<i class="feed icon" />
|
||||
<div class="content">
|
||||
Mute activity
|
||||
{{ $t('components.manage.moderation.InstancePolicyCard.muteActivityRule') }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
@ -57,7 +57,7 @@ const summary = useMarkdown(() => props.object.summary)
|
|||
>
|
||||
<i class="bell icon" />
|
||||
<div class="content">
|
||||
Mute notifications
|
||||
{{ $t('components.manage.moderation.InstancePolicyCard.muteNotificationsRule') }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
@ -66,14 +66,14 @@ const summary = useMarkdown(() => props.object.summary)
|
|||
>
|
||||
<i class="file icon" />
|
||||
<div class="content">
|
||||
Reject media
|
||||
{{ $t('components.manage.moderation.InstancePolicyCard.rejectMediaRule') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="summary">
|
||||
<div class="ui hidden divider" />
|
||||
<p><strong>Reason</strong></p>
|
||||
<p><strong>{{ $t('components.manage.moderation.InstancePolicyCard.ruleReason') }}</strong></p>
|
||||
<sanitized-html :html="summary" />
|
||||
</div>
|
||||
<div class="ui hidden divider" />
|
||||
|
@ -82,7 +82,7 @@ const summary = useMarkdown(() => props.object.summary)
|
|||
@click="emit('update')"
|
||||
>
|
||||
<i class="edit icon" />
|
||||
Edit
|
||||
{{ $t('components.manage.moderation.InstancePolicyCard.editButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -27,20 +27,20 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
const { t } = useI18n()
|
||||
|
||||
const labels = computed(() => ({
|
||||
summaryHelp: t("Explain why you're applying this policy: this will help you remember why you added this rule. Depending on your pod configuration, this may be displayed publicly to help users understand the moderation rules in place."),
|
||||
isActiveHelp: t('Use this setting to temporarily enable/disable the policy without completely removing it.'),
|
||||
blockAllHelp: t('Block everything from this account or domain. This will prevent any interaction with the entity, and purge related content (uploads, libraries, follows, etc.)'),
|
||||
summaryHelp: t('components.manage.moderation.InstancePolicyForm.summaryHelp'),
|
||||
isActiveHelp: t('components.manage.moderation.InstancePolicyForm.isActiveHelp'),
|
||||
blockAllHelp: t('components.manage.moderation.InstancePolicyForm.blockAllHelp'),
|
||||
silenceActivity: {
|
||||
help: t('Hide account or domain content, except from followers.'),
|
||||
label: t('Mute activity')
|
||||
help: t('components.manage.moderation.InstancePolicyForm.silenceActivityHelp'),
|
||||
label: t('components.manage.moderation.InstancePolicyForm.silenceActivityLabel')
|
||||
},
|
||||
silenceNotifications: {
|
||||
help: t('Prevent account or domain from triggering notifications, except from followers.'),
|
||||
label: t('Mute notifications')
|
||||
help: t('components.manage.moderation.InstancePolicyForm.silenceNotificationsHelp'),
|
||||
label: t('components.manage.moderation.InstancePolicyForm.silenceNotificationsLabel')
|
||||
},
|
||||
rejectMedia: {
|
||||
help: t('Do not download any media file (audio, album cover, account avatar…) from this account or domain. This will purge existing content as well.'),
|
||||
label: t('Reject media')
|
||||
help: t('components.manage.moderation.InstancePolicyForm.rejectMediaHelp'),
|
||||
label: t('components.manage.moderation.InstancePolicyForm.rejectMediaLabel')
|
||||
}
|
||||
}))
|
||||
|
||||
|
@ -122,16 +122,16 @@ const remove = async () => {
|
|||
@submit.prevent="createOrUpdate"
|
||||
>
|
||||
<h3 class="ui header">
|
||||
<translate
|
||||
<span
|
||||
v-if="object"
|
||||
>
|
||||
Edit moderation rule
|
||||
</translate>
|
||||
<translate
|
||||
{{ $t('components.manage.moderation.InstancePolicyForm.editRuleHeader') }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
Add a new moderation rule
|
||||
</translate>
|
||||
{{ $t('components.manage.moderation.InstancePolicyForm.addRuleHeader') }}
|
||||
</span>
|
||||
</h3>
|
||||
<div
|
||||
v-if="errors && errors.length > 0"
|
||||
|
@ -139,7 +139,7 @@ const remove = async () => {
|
|||
class="ui negative message"
|
||||
>
|
||||
<h4 class="header">
|
||||
Error while creating rule
|
||||
{{ $t('components.manage.moderation.InstancePolicyForm.createRuleFailureHeader') }}
|
||||
</h4>
|
||||
<ul class="list">
|
||||
<li
|
||||
|
@ -162,19 +162,19 @@ const remove = async () => {
|
|||
type="checkbox"
|
||||
>
|
||||
<label for="policy-is-active">
|
||||
<translate
|
||||
<span
|
||||
v-if="current.isActive"
|
||||
>Enabled</translate>
|
||||
<translate
|
||||
>{{ $t('components.manage.moderation.InstancePolicyForm.policyEnabled') }}</span>
|
||||
<span
|
||||
v-else
|
||||
>Disabled</translate>
|
||||
>{{ $t('components.manage.moderation.InstancePolicyForm.policyDisabled') }}</span>
|
||||
<tooltip :content="labels.isActiveHelp" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="policy-summary">
|
||||
Reason
|
||||
{{ $t('components.manage.moderation.InstancePolicyForm.policyReasonLabel') }}
|
||||
<tooltip :content="labels.summaryHelp" />
|
||||
</label>
|
||||
<textarea
|
||||
|
@ -192,13 +192,13 @@ const remove = async () => {
|
|||
type="checkbox"
|
||||
>
|
||||
<label for="policy-is-active">
|
||||
Block everything
|
||||
{{ $t('components.manage.moderation.InstancePolicyForm.blockAllLabel') }}
|
||||
<tooltip :content="labels.blockAllHelp" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui horizontal divider">
|
||||
Or customize your rule
|
||||
{{ $t('components.manage.moderation.InstancePolicyForm.customizeRuleMessage') }}
|
||||
</div>
|
||||
<div
|
||||
v-for="(config, key) in fieldConfig"
|
||||
|
@ -223,42 +223,42 @@ const remove = async () => {
|
|||
class="ui basic left floated button"
|
||||
@click.prevent="emit('cancel')"
|
||||
>
|
||||
Cancel
|
||||
{{ $t('components.manage.moderation.InstancePolicyForm.cancelButton') }}
|
||||
</button>
|
||||
<button
|
||||
:class="['ui', 'right', 'floated', 'success', {'disabled loading': isLoading}, 'button']"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
<translate
|
||||
<span
|
||||
v-if="object"
|
||||
>
|
||||
Update
|
||||
</translate>
|
||||
<translate
|
||||
{{ $t('components.manage.moderation.InstancePolicyForm.updateButton') }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
Create
|
||||
</translate>
|
||||
{{ $t('components.manage.moderation.InstancePolicyForm.createButton') }}
|
||||
</span>
|
||||
</button>
|
||||
<dangerous-button
|
||||
v-if="object"
|
||||
class="ui right floated basic danger button"
|
||||
@confirm="remove"
|
||||
>
|
||||
Delete
|
||||
{{ $t('components.manage.moderation.InstancePolicyForm.deleteButton') }}
|
||||
<template #modal-header>
|
||||
<p>
|
||||
Delete this moderation rule?
|
||||
{{ $t('components.manage.moderation.InstancePolicyForm.deleteRuleModalHeader') }}
|
||||
</p>
|
||||
</template>
|
||||
<template #modal-content>
|
||||
<p>
|
||||
This action is irreversible.
|
||||
{{ $t('components.manage.moderation.InstancePolicyForm.deleteRuleModalMessage') }}
|
||||
</p>
|
||||
</template>
|
||||
<template #modal-confirm>
|
||||
<div>
|
||||
Delete moderation rule
|
||||
{{ $t('components.manage.moderation.InstancePolicyForm.deleteRuleModalConfirm') }}
|
||||
</div>
|
||||
</template>
|
||||
</dangerous-button>
|
||||
|
|
|
@ -62,18 +62,14 @@ const fetchData = async () => {
|
|||
>
|
||||
<i class="shield icon" />
|
||||
<slot>
|
||||
Moderation rules…
|
||||
{{ $t('components.manage.moderation.InstancePolicyModal.moderationRulesHeader') }}
|
||||
</slot>
|
||||
<semantic-modal
|
||||
v-model:show="show"
|
||||
@show="fetchData"
|
||||
>
|
||||
<h4 class="header">
|
||||
<translate
|
||||
:translate-params="{obj: target}"
|
||||
>
|
||||
Manage moderation rules for %{ obj }
|
||||
</translate>
|
||||
{{ $t('components.manage.moderation.InstancePolicyModal.manageRulesHeader', {obj: target}) }}
|
||||
</h4>
|
||||
<div class="content">
|
||||
<div class="description">
|
||||
|
@ -88,7 +84,7 @@ const fetchData = async () => {
|
|||
>
|
||||
<header class="ui header">
|
||||
<h3>
|
||||
This entity is subject to specific moderation rules
|
||||
{{ $t('components.manage.moderation.InstancePolicyModal.manageRulesHeader', {obj: target}) }}
|
||||
</h3>
|
||||
</header>
|
||||
</instance-policy-card>
|
||||
|
@ -107,7 +103,7 @@ const fetchData = async () => {
|
|||
</div>
|
||||
<div class="actions">
|
||||
<button class="ui deny button">
|
||||
Close
|
||||
{{ $t('components.manage.moderation.InstancePolicyModal.closeButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</semantic-modal>
|
||||
|
|
|
@ -18,7 +18,7 @@ const props = defineProps<Props>()
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
summaryPlaceholder: t('Describe what actions have been taken, or any other related updates…')
|
||||
summaryPlaceholder: t('components.manage.moderation.NoteForm.summaryPlaceholder')
|
||||
}))
|
||||
|
||||
const summary = ref('')
|
||||
|
@ -56,7 +56,7 @@ const submit = async () => {
|
|||
class="ui negative message"
|
||||
>
|
||||
<h4 class="header">
|
||||
Error while submitting note
|
||||
{{ $t('components.manage.moderation.NoteForm.submissionFailureHeader') }}
|
||||
</h4>
|
||||
<ul class="list">
|
||||
<li
|
||||
|
@ -81,7 +81,7 @@ const submit = async () => {
|
|||
type="submit"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
Add note
|
||||
{{ $t('components.manage.moderation.NoteForm.addNoteButton') }}
|
||||
</button>
|
||||
</form>
|
||||
</template>
|
||||
|
|
|
@ -64,22 +64,22 @@ const remove = async (note: Note) => {
|
|||
@confirm="remove(note)"
|
||||
>
|
||||
<i class="trash icon" />
|
||||
Delete
|
||||
{{ $t('components.manage.moderation.NotesThread.deleteButton') }}
|
||||
<template #modal-header>
|
||||
<p>
|
||||
Delete this note?
|
||||
{{ $t('components.manage.moderation.NotesThread.deleteModalHeader') }}
|
||||
</p>
|
||||
</template>
|
||||
<template #modal-content>
|
||||
<div>
|
||||
<p>
|
||||
The note will be removed. This action is irreversible.
|
||||
{{ $t('components.manage.moderation.NotesThread.deleteModalMessage') }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<template #modal-confirm>
|
||||
<p>
|
||||
Delete
|
||||
{{ $t('components.manage.moderation.NotesThread.deleteButton') }}
|
||||
</p>
|
||||
</template>
|
||||
</dangerous-button>
|
||||
|
|
|
@ -66,10 +66,10 @@ const actions = computed(() => {
|
|||
const deleteUrl = typeConfig.getDeleteUrl?.(target.value)
|
||||
return deleteUrl
|
||||
? [{
|
||||
label: t('Delete reported object'),
|
||||
modalHeader: t('Delete reported object?'),
|
||||
modalContent: t('This will delete the object associated with this report and mark the report as resolved. The deletion is irreversible.'),
|
||||
modalConfirmLabel: t('Delete'),
|
||||
label: t('components.manage.moderation.ReportCard.deleteLabel'),
|
||||
modalHeader: t('components.manage.moderation.ReportCard.deleteModalHeader'),
|
||||
modalContent: t('components.manage.moderation.ReportCard.deleteModalMessage'),
|
||||
modalConfirmLabel: t('components.manage.moderation.ReportCard.deleteConfirmLabel'),
|
||||
icon: 'x',
|
||||
iconColor: 'danger',
|
||||
show: (obj: Report) => { return !!obj.target },
|
||||
|
@ -141,12 +141,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
<div class="content">
|
||||
<h4 class="header">
|
||||
<router-link :to="{name: 'manage.moderation.reports.detail', params: {id: obj.uuid}}">
|
||||
<translate
|
||||
|
||||
:translate-params="{id: obj.uuid.substring(0, 8)}"
|
||||
>
|
||||
Report %{ id }
|
||||
</translate>
|
||||
{{ $t('components.manage.moderation.ReportCard.reportHeader', {id: obj.uuid.substring(0, 8)}) }}
|
||||
</router-link>
|
||||
<collapse-link
|
||||
v-model="isCollapsed"
|
||||
|
@ -161,7 +156,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Submitted by
|
||||
{{ $t('components.manage.moderation.ReportCard.submittedByLabel') }}
|
||||
</td>
|
||||
<td>
|
||||
<div v-if="obj.submitter">
|
||||
|
@ -177,7 +172,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Category
|
||||
{{ $t('components.manage.moderation.ReportCard.categoryLabel') }}
|
||||
</td>
|
||||
<td>
|
||||
<report-category-dropdown
|
||||
|
@ -191,7 +186,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Creation date
|
||||
{{ $t('components.manage.moderation.ReportCard.creationDateLabel') }}
|
||||
</td>
|
||||
<td>
|
||||
<human-date
|
||||
|
@ -208,22 +203,22 @@ const handleRemovedNote = (uuid: string) => {
|
|||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Status
|
||||
{{ $t('components.manage.moderation.ReportCard.statusLabel') }}
|
||||
</td>
|
||||
<td v-if="obj.is_handled">
|
||||
<span v-if="obj.is_handled">
|
||||
<i class="success check icon" />
|
||||
Resolved
|
||||
{{ $t('components.manage.moderation.ReportCard.resolvedStatus') }}
|
||||
</span>
|
||||
</td>
|
||||
<td v-else>
|
||||
<i class="danger x icon" />
|
||||
Unresolved
|
||||
{{ $t('components.manage.moderation.ReportCard.unresolvedStatus') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Assigned to
|
||||
{{ $t('components.manage.moderation.ReportCard.assignedToLabel') }}
|
||||
</td>
|
||||
<td>
|
||||
<div v-if="obj.assigned_to">
|
||||
|
@ -232,16 +227,16 @@ const handleRemovedNote = (uuid: string) => {
|
|||
:actor="obj.assigned_to"
|
||||
/>
|
||||
</div>
|
||||
<translate
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
N/A
|
||||
</translate>
|
||||
{{ $t('components.manage.moderation.ReportCard.notApplicable') }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Resolution date
|
||||
{{ $t('components.manage.moderation.ReportCard.resolutionDateLabel') }}
|
||||
</td>
|
||||
<td>
|
||||
<human-date
|
||||
|
@ -249,16 +244,16 @@ const handleRemovedNote = (uuid: string) => {
|
|||
:date="obj.handled_date"
|
||||
:icon="true"
|
||||
/>
|
||||
<translate
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
N/A
|
||||
</translate>
|
||||
{{ $t('components.manage.moderation.ReportCard.notApplicable') }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Internal notes
|
||||
{{ $t('components.manage.moderation.ReportCard.internalNotesLabel') }}
|
||||
</td>
|
||||
<td>
|
||||
<i class="comment icon" />
|
||||
|
@ -278,7 +273,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
<div class="ui stackable two column grid">
|
||||
<div class="column">
|
||||
<h3>
|
||||
Message
|
||||
{{ $t('components.manage.moderation.ReportCard.messageHeader') }}
|
||||
</h3>
|
||||
<expandable-div
|
||||
v-if="summary"
|
||||
|
@ -290,14 +285,14 @@ const handleRemovedNote = (uuid: string) => {
|
|||
</div>
|
||||
<aside class="column">
|
||||
<h3>
|
||||
Reported object
|
||||
{{ $t('components.manage.moderation.ReportCard.reportedObjectHeader') }}
|
||||
</h3>
|
||||
<div
|
||||
v-if="!obj.target"
|
||||
role="alert"
|
||||
class="ui warning message"
|
||||
>
|
||||
The object associated with this report was deleted.
|
||||
{{ $t('components.manage.moderation.ReportCard.objectDeletedWarning') }}
|
||||
</div>
|
||||
<router-link
|
||||
v-if="target && configs[target.type].urls.getDetail"
|
||||
|
@ -305,7 +300,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
:to="configs[target.type].urls.getDetail?.(obj.target_state) ?? '/'"
|
||||
>
|
||||
<i class="eye icon" />
|
||||
View public page
|
||||
{{ $t('components.manage.moderation.ReportCard.publicPageLink') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
v-if="target && configs[target.type].urls.getAdminDetail"
|
||||
|
@ -313,13 +308,13 @@ const handleRemovedNote = (uuid: string) => {
|
|||
:to="configs[target.type].urls.getAdminDetail?.(obj.target_state) ?? '/'"
|
||||
>
|
||||
<i class="wrench icon" />
|
||||
Open in moderation interface
|
||||
{{ $t('components.manage.moderation.ReportCard.moderationLink') }}
|
||||
</router-link>
|
||||
<table class="ui very basic unstackable table">
|
||||
<tbody>
|
||||
<tr v-if="target">
|
||||
<td>
|
||||
Type
|
||||
{{ $t('components.manage.moderation.ReportCard.objectTypeLabel') }}
|
||||
</td>
|
||||
<td colspan="2">
|
||||
<i :class="[configs[target.type].icon, 'icon']" />
|
||||
|
@ -328,7 +323,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
</tr>
|
||||
<tr v-if="obj.target_owner && (!target || target.type !== 'account')">
|
||||
<td>
|
||||
Owner
|
||||
{{ $t('components.manage.moderation.ReportCard.objectOwnerLabel') }}
|
||||
</td>
|
||||
<td>
|
||||
<actor-link
|
||||
|
@ -347,7 +342,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
</tr>
|
||||
<tr v-if="target && target.type === 'account'">
|
||||
<td>
|
||||
Account
|
||||
{{ $t('components.manage.moderation.ReportCard.accountLabel') }}
|
||||
</td>
|
||||
<td>
|
||||
<actor-link
|
||||
|
@ -366,17 +361,17 @@ const handleRemovedNote = (uuid: string) => {
|
|||
</tr>
|
||||
<tr v-if="obj.target_state.is_local">
|
||||
<td>
|
||||
Domain
|
||||
{{ $t('components.manage.moderation.ReportCard.domainLabel') }}
|
||||
</td>
|
||||
<td colspan="2">
|
||||
<i class="home icon" />
|
||||
Local
|
||||
{{ $t('components.manage.moderation.ReportCard.localLabel') }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-else-if="obj.target_state.domain">
|
||||
<td>
|
||||
<router-link :to="{name: 'manage.moderation.domains.detail', params: { id: obj.target_state.domain }}">
|
||||
Domain
|
||||
{{ $t('components.manage.moderation.ReportCard.domainLabel') }}
|
||||
</router-link>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -405,7 +400,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
v-else
|
||||
colspan="2"
|
||||
>
|
||||
N/A
|
||||
{{ $t('components.manage.moderation.ReportCard.notApplicable') }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -415,7 +410,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
<div class="ui stackable two column grid">
|
||||
<div class="column">
|
||||
<h3>
|
||||
Internal notes
|
||||
{{ $t('components.manage.moderation.ReportCard.internalNotesLabel') }}
|
||||
</h3>
|
||||
<notes-thread
|
||||
:notes="obj.notes"
|
||||
|
@ -428,7 +423,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
</div>
|
||||
<div class="column">
|
||||
<h3>
|
||||
Actions
|
||||
{{ $t('components.manage.moderation.ReportCard.actionsLabel') }}
|
||||
</h3>
|
||||
<div class="ui labelled icon basic buttons">
|
||||
<button
|
||||
|
@ -437,7 +432,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
@click="resolveReport(true)"
|
||||
>
|
||||
<i class="success check icon" />
|
||||
Resolve
|
||||
{{ $t('components.manage.moderation.ReportCard.resolveLabel') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="obj.is_handled === true"
|
||||
|
@ -445,7 +440,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
@click="resolveReport(false)"
|
||||
>
|
||||
<i class="warning redo icon" />
|
||||
Unresolve
|
||||
{{ $t('components.manage.moderation.ReportCard.unresolveLabel') }}
|
||||
</button>
|
||||
<template
|
||||
v-for="action in actions"
|
||||
|
|
|
@ -67,12 +67,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
<div class="content">
|
||||
<h4 class="header">
|
||||
<router-link :to="{name: 'manage.moderation.requests.detail', params: {id: obj.uuid}}">
|
||||
<translate
|
||||
|
||||
:translate-params="{id: obj.uuid.substring(0, 8)}"
|
||||
>
|
||||
Request %{ id }
|
||||
</translate>
|
||||
{{ $t('components.manage.moderation.UserRequestCard.requestHeader', {id: obj.uuid.substring(0, 8)}) }}
|
||||
</router-link>
|
||||
<collapse-link
|
||||
v-model="isCollapsed"
|
||||
|
@ -87,7 +82,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Submitted by
|
||||
{{ $t('components.manage.moderation.UserRequestCard.submittedByLabel') }}
|
||||
</td>
|
||||
<td>
|
||||
<actor-link
|
||||
|
@ -98,7 +93,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Creation date
|
||||
{{ $t('components.manage.moderation.UserRequestCard.creationDateLabel') }}
|
||||
</td>
|
||||
<td>
|
||||
<human-date
|
||||
|
@ -115,26 +110,26 @@ const handleRemovedNote = (uuid: string) => {
|
|||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Status
|
||||
{{ $t('components.manage.moderation.UserRequestCard.statusLabel') }}
|
||||
</td>
|
||||
<td>
|
||||
<template v-if="obj.status === 'pending'">
|
||||
<i class="warning hourglass icon" />
|
||||
Pending
|
||||
{{ $t('components.manage.moderation.UserRequestCard.pendingStatus') }}
|
||||
</template>
|
||||
<template v-else-if="obj.status === 'refused'">
|
||||
<i class="danger x icon" />
|
||||
Refused
|
||||
{{ $t('components.manage.moderation.UserRequestCard.refusedStatus') }}
|
||||
</template>
|
||||
<template v-else-if="obj.status === 'approved'">
|
||||
<i class="success check icon" />
|
||||
Approved
|
||||
{{ $t('components.manage.moderation.UserRequestCard.approvedStatus') }}
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Assigned to
|
||||
{{ $t('components.manage.moderation.UserRequestCard.assignedToLabel') }}
|
||||
</td>
|
||||
<td>
|
||||
<div v-if="obj.assigned_to">
|
||||
|
@ -143,16 +138,16 @@ const handleRemovedNote = (uuid: string) => {
|
|||
:actor="obj.assigned_to"
|
||||
/>
|
||||
</div>
|
||||
<translate
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
N/A
|
||||
</translate>
|
||||
{{ $t('components.manage.moderation.UserRequestCard.notApplicable') }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Resolution date
|
||||
{{ $t('components.manage.moderation.UserRequestCard.resolutionDateLabel') }}
|
||||
</td>
|
||||
<td>
|
||||
<human-date
|
||||
|
@ -160,16 +155,16 @@ const handleRemovedNote = (uuid: string) => {
|
|||
:date="obj.handled_date"
|
||||
:icon="true"
|
||||
/>
|
||||
<translate
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
N/A
|
||||
</translate>
|
||||
{{ $t('components.manage.moderation.UserRequestCard.notApplicable') }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Internal notes
|
||||
{{ $t('components.manage.moderation.UserRequestCard.internalNotesLabel') }}
|
||||
</td>
|
||||
<td>
|
||||
<i class="comment icon" />
|
||||
|
@ -189,10 +184,10 @@ const handleRemovedNote = (uuid: string) => {
|
|||
<div class="ui stackable two column grid">
|
||||
<div class="column">
|
||||
<h3>
|
||||
Message
|
||||
{{ $t('components.manage.moderation.UserRequestCard.messageHeader') }}
|
||||
</h3>
|
||||
<p>
|
||||
This user wants to sign-up on your pod.
|
||||
{{ $t('components.manage.moderation.UserRequestCard.messageBody') }}
|
||||
</p>
|
||||
<template v-if="obj.metadata">
|
||||
<div class="ui hidden divider" />
|
||||
|
@ -204,11 +199,11 @@ const handleRemovedNote = (uuid: string) => {
|
|||
<p v-if="value">
|
||||
{{ value }}
|
||||
</p>
|
||||
<translate
|
||||
<span
|
||||
v-else
|
||||
>
|
||||
N/A
|
||||
</translate>
|
||||
{{ $t('components.manage.moderation.UserRequestCard.notApplicable') }}
|
||||
</span>
|
||||
<div class="ui hidden divider" />
|
||||
</div>
|
||||
</template>
|
||||
|
@ -216,7 +211,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
<aside class="column">
|
||||
<div v-if="obj.status != 'approved'">
|
||||
<h3>
|
||||
Actions
|
||||
{{ $t('components.manage.moderation.UserRequestCard.actionsHeader') }}
|
||||
</h3>
|
||||
<div class="ui labelled icon basic buttons">
|
||||
<button
|
||||
|
@ -225,7 +220,7 @@ const handleRemovedNote = (uuid: string) => {
|
|||
@click="approve(true)"
|
||||
>
|
||||
<i class="success check icon" />
|
||||
Approve
|
||||
{{ $t('components.manage.moderation.UserRequestCard.approveButton') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="obj.status === 'pending'"
|
||||
|
@ -233,12 +228,12 @@ const handleRemovedNote = (uuid: string) => {
|
|||
@click="approve(false)"
|
||||
>
|
||||
<i class="danger x icon" />
|
||||
Refuse
|
||||
{{ $t('components.manage.moderation.UserRequestCard.rejectButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<h3>
|
||||
Internal notes
|
||||
{{ $t('components.manage.moderation.UserRequestCard.internalNotesLabel') }}
|
||||
</h3>
|
||||
<notes-thread
|
||||
:notes="obj.notes"
|
||||
|
|
|
@ -17,7 +17,7 @@ const router = useRouter()
|
|||
const store = useStore()
|
||||
|
||||
const labels = computed(() => ({
|
||||
placeholder: t('Leave empty for a random code')
|
||||
placeholder: t('components.manage.users.InvitationForm.placeholder')
|
||||
}))
|
||||
|
||||
const invitations = reactive([] as Invitation[])
|
||||
|
@ -56,7 +56,7 @@ const getUrl = (code: string) => store.getters['instance/absoluteUrl'](router.re
|
|||
class="ui negative message"
|
||||
>
|
||||
<h4 class="header">
|
||||
Error while creating invitation
|
||||
{{ $t('components.manage.users.InvitationForm.inviteCreateFailureHeader') }}
|
||||
</h4>
|
||||
<ul class="list">
|
||||
<li
|
||||
|
@ -69,7 +69,7 @@ const getUrl = (code: string) => store.getters['instance/absoluteUrl'](router.re
|
|||
</div>
|
||||
<div class="inline fields">
|
||||
<div class="ui field">
|
||||
<label for="invitation-code">Invitation code</label>
|
||||
<label for="invitation-code">{{ $t('components.manage.users.InvitationForm.invitationCodeLabel') }}</label>
|
||||
<input
|
||||
v-model="code"
|
||||
for="invitation-code"
|
||||
|
@ -84,7 +84,7 @@ const getUrl = (code: string) => store.getters['instance/absoluteUrl'](router.re
|
|||
:disabled="isLoading"
|
||||
type="submit"
|
||||
>
|
||||
Get a new invitation
|
||||
{{ $t('components.manage.users.InvitationForm.newInviteCodeButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -95,10 +95,10 @@ const getUrl = (code: string) => store.getters['instance/absoluteUrl'](router.re
|
|||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Code
|
||||
{{ $t('components.manage.users.InvitationForm.codeLabel') }}
|
||||
</th>
|
||||
<th>
|
||||
Share link
|
||||
{{ $t('components.manage.users.InvitationForm.shareLinkLabel') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -121,7 +121,7 @@ const getUrl = (code: string) => store.getters['instance/absoluteUrl'](router.re
|
|||
class="ui basic button"
|
||||
@click="invitations = []"
|
||||
>
|
||||
Clear
|
||||
{{ $t('components.manage.users.InvitationForm.clearButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -48,7 +48,7 @@ const actionFilters = computed(() => ({ q: query.value, ...props.filters }))
|
|||
const actions = computed(() => [
|
||||
{
|
||||
name: 'delete',
|
||||
label: t('Delete'),
|
||||
label: t('components.manage.users.InvitationsTable.deleteLabel'),
|
||||
filterCheckable: (obj: { users: unknown[], expiration_date: Date }) => {
|
||||
return obj.users.length === 0 && moment().isBefore(obj.expiration_date)
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ fetchData()
|
|||
|
||||
const sharedLabels = useSharedLabels()
|
||||
const labels = computed(() => ({
|
||||
searchPlaceholder: t('Search by username, e-mail address, code…')
|
||||
searchPlaceholder: t('components.manage.users.InvitationsTable.searchPlaceholder')
|
||||
}))
|
||||
</script>
|
||||
|
||||
|
@ -98,7 +98,7 @@ const labels = computed(() => ({
|
|||
<div class="ui inline form">
|
||||
<div class="fields">
|
||||
<div class="ui field">
|
||||
<label for="invitations-search">Search</label>
|
||||
<label for="invitations-search">{{ $t('components.manage.users.InvitationsTable.searchLabel') }}</label>
|
||||
<input
|
||||
id="invitations-search"
|
||||
v-model="query"
|
||||
|
@ -108,7 +108,7 @@ const labels = computed(() => ({
|
|||
>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="invitations-ordering">Ordering</label>
|
||||
<label for="invitations-ordering">{{ $t('components.manage.users.InvitationsTable.orderingLabel') }}</label>
|
||||
<select
|
||||
id="invitations-ordering"
|
||||
v-model="ordering"
|
||||
|
@ -124,20 +124,20 @@ const labels = computed(() => ({
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="invitations-status">Status</label>
|
||||
<label for="invitations-status">{{ $t('components.manage.users.InvitationsTable.statusLabel') }}</label>
|
||||
<select
|
||||
id="invitations-status"
|
||||
v-model="isOpen"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option :value="null">
|
||||
All
|
||||
{{ $t('components.manage.users.InvitationsTable.allOption') }}
|
||||
</option>
|
||||
<option :value="true">
|
||||
Open
|
||||
{{ $t('components.manage.users.InvitationsTable.openStatus') }}
|
||||
</option>
|
||||
<option :value="false">
|
||||
Expired/used
|
||||
{{ $t('components.manage.users.InvitationsTable.expiredStatus') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -160,22 +160,22 @@ const labels = computed(() => ({
|
|||
>
|
||||
<template #header-cells>
|
||||
<th>
|
||||
Owner
|
||||
{{ $t('components.manage.users.InvitationsTable.ownerTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
User
|
||||
{{ $t('components.manage.users.InvitationsTable.userTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Status
|
||||
{{ $t('components.manage.users.InvitationsTable.statusTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Creation date
|
||||
{{ $t('components.manage.users.InvitationsTable.creationDateTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Expiration date
|
||||
{{ $t('components.manage.users.InvitationsTable.expirationDateTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Code
|
||||
{{ $t('components.manage.users.InvitationsTable.codeTableHeader') }}
|
||||
</th>
|
||||
</template>
|
||||
<template
|
||||
|
@ -195,15 +195,15 @@ const labels = computed(() => ({
|
|||
<span
|
||||
v-if="scope.obj.users.length > 0"
|
||||
class="ui success basic label"
|
||||
>Used</span>
|
||||
>{{ $t('components.manage.users.InvitationsTable.usedStatusLabel') }}</span>
|
||||
<span
|
||||
v-else-if="moment().isAfter(scope.obj.expiration_date)"
|
||||
class="ui danger basic label"
|
||||
>Expired</span>
|
||||
>{{ $t('components.manage.users.InvitationsTable.expiredStatusLabel') }}</span>
|
||||
<span
|
||||
v-else
|
||||
class="ui basic label"
|
||||
>Not used</span>
|
||||
>{{ $t('components.manage.users.InvitationsTable.unusedStatusLabel') }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<human-date :date="scope.obj.creation_date" />
|
||||
|
@ -227,14 +227,7 @@ const labels = computed(() => ({
|
|||
/>
|
||||
|
||||
<span v-if="result && result.results.length > 0">
|
||||
<translate
|
||||
|
||||
translate-plural="Showing results %{ start } to %{ end } from %{ total }"
|
||||
:translate-params="{start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}"
|
||||
:translate-n="result.count"
|
||||
>
|
||||
Showing one result
|
||||
</translate>
|
||||
{{ $t('components.manage.users.InvitationsTable.resultsDisplay', {start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -44,15 +44,15 @@ const orderingOptions: [OrderingField, keyof typeof sharedLabels.filters][] = [
|
|||
const permissions = computed(() => [
|
||||
{
|
||||
code: 'library',
|
||||
label: t('Library')
|
||||
label: t('components.manage.users.UsersTable.libraryLabel')
|
||||
},
|
||||
{
|
||||
code: 'moderation',
|
||||
label: t('Moderation')
|
||||
label: t('components.manage.users.UsersTable.moderationLabel')
|
||||
},
|
||||
{
|
||||
code: 'settings',
|
||||
label: t('Settings')
|
||||
label: t('components.manage.users.UsersTable.settingsLabel')
|
||||
}
|
||||
])
|
||||
|
||||
|
@ -91,7 +91,7 @@ fetchData()
|
|||
|
||||
const sharedLabels = useSharedLabels()
|
||||
const labels = computed(() => ({
|
||||
searchPlaceholder: t('Search by username, e-mail address, name…')
|
||||
searchPlaceholder: t('components.manage.users.UsersTable.searchPlaceholder')
|
||||
}))
|
||||
</script>
|
||||
|
||||
|
@ -100,7 +100,7 @@ const labels = computed(() => ({
|
|||
<div class="ui inline form">
|
||||
<div class="fields">
|
||||
<div class="ui field">
|
||||
<label for="users-search">Search</label>
|
||||
<label for="users-search">{{ $t('components.manage.users.UsersTable.searchLabel') }}</label>
|
||||
<input
|
||||
id="users-search"
|
||||
v-model="query"
|
||||
|
@ -110,7 +110,7 @@ const labels = computed(() => ({
|
|||
>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="users-ordering">Ordering</label>
|
||||
<label for="users-ordering">{{ $t('components.manage.users.UsersTable.orderingLabel') }}</label>
|
||||
<select
|
||||
id="users-ordering"
|
||||
v-model="ordering"
|
||||
|
@ -126,17 +126,17 @@ const labels = computed(() => ({
|
|||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="users-ordering-direction">Order</label>
|
||||
<label for="users-ordering-direction">{{ $t('components.manage.users.UsersTable.orderingDirectionLabel') }}</label>
|
||||
<select
|
||||
id="users-ordering-direction"
|
||||
v-model="orderingDirection"
|
||||
class="ui dropdown"
|
||||
>
|
||||
<option value="+">
|
||||
Ascending
|
||||
{{ $t('components.manage.users.UsersTable.ascendingOrdering') }}
|
||||
</option>
|
||||
<option value="-">
|
||||
Descending
|
||||
{{ $t('components.manage.users.UsersTable.descendingOrdering') }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -159,25 +159,25 @@ const labels = computed(() => ({
|
|||
>
|
||||
<template #header-cells>
|
||||
<th>
|
||||
Username
|
||||
{{ $t('components.manage.users.UsersTable.usernameTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Email
|
||||
{{ $t('components.manage.users.UsersTable.emailTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Account status
|
||||
{{ $t('components.manage.users.UsersTable.accountStatusTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Sign-up
|
||||
{{ $t('components.manage.users.UsersTable.signupTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Last activity
|
||||
{{ $t('components.manage.users.UsersTable.lastActivityTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Permissions
|
||||
{{ $t('components.manage.users.UsersTable.permissionsTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Status
|
||||
{{ $t('components.manage.users.UsersTable.statusTableHeader') }}
|
||||
</th>
|
||||
</template>
|
||||
<template
|
||||
|
@ -204,11 +204,11 @@ const labels = computed(() => ({
|
|||
<span
|
||||
v-if="scope.obj.is_active"
|
||||
class="ui basic success label"
|
||||
>Active</span>
|
||||
>{{ $t('components.manage.users.UsersTable.activeStatus') }}</span>
|
||||
<span
|
||||
v-else
|
||||
class="ui basic label"
|
||||
>Inactive</span>
|
||||
>{{ $t('components.manage.users.UsersTable.inactiveStatus') }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<human-date :date="scope.obj.date_joined" />
|
||||
|
@ -219,7 +219,7 @@ const labels = computed(() => ({
|
|||
:date="scope.obj.last_activity"
|
||||
/>
|
||||
<template v-else>
|
||||
N/A
|
||||
{{ $t('components.manage.users.UsersTable.notApplicable') }}
|
||||
</template>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -237,15 +237,15 @@ const labels = computed(() => ({
|
|||
<span
|
||||
v-if="scope.obj.is_superuser"
|
||||
class="ui pink label"
|
||||
>Admin</span>
|
||||
>{{ $t('components.manage.users.UsersTable.adminPermission') }}</span>
|
||||
<span
|
||||
v-else-if="scope.obj.is_staff"
|
||||
class="ui purple label"
|
||||
>Staff member</span>
|
||||
>{{ $t('components.manage.users.UsersTable.staffPermission') }}</span>
|
||||
<span
|
||||
v-else
|
||||
class="ui basic label"
|
||||
>Regular user</span>
|
||||
>{{ $t('components.manage.users.UsersTable.regularPermission') }}</span>
|
||||
</td>
|
||||
</template>
|
||||
</action-table>
|
||||
|
@ -260,14 +260,7 @@ const labels = computed(() => ({
|
|||
/>
|
||||
|
||||
<span v-if="result && result.results.length > 0">
|
||||
<translate
|
||||
|
||||
translate-plural="Showing results %{ start } to %{ end } from %{ total }"
|
||||
:translate-params="{start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}"
|
||||
:translate-n="result.count"
|
||||
>
|
||||
Showing one result
|
||||
</translate>
|
||||
{{ $t('components.manage.users.UsersTable.resultsDisplay', {start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -45,7 +45,7 @@ const hide = async () => {
|
|||
store.state.moderation.lastUpdate = new Date()
|
||||
store.commit('moderation/contentFilter', response.data)
|
||||
store.commit('ui/addMessage', {
|
||||
content: t('Content filter successfully added'),
|
||||
content: t('components.moderation.FilterModal.contentSuccessMessage'),
|
||||
date: new Date()
|
||||
})
|
||||
} catch (error) {
|
||||
|
@ -59,14 +59,11 @@ const hide = async () => {
|
|||
|
||||
<template>
|
||||
<semantic-modal v-model:show="show">
|
||||
<h4 class="header">
|
||||
<translate
|
||||
v-if="type === 'artist'"
|
||||
|
||||
:translate-params="{name: target?.name}"
|
||||
>
|
||||
Do you want to hide content from artist "%{ name }"?
|
||||
</translate>
|
||||
<h4
|
||||
v-if="type === 'artist'"
|
||||
class="header"
|
||||
>
|
||||
{{ $t('components.moderation.FilterModal.hideContentHeader', {name: target?.name}) }}
|
||||
</h4>
|
||||
<div class="scrolling content">
|
||||
<div class="description">
|
||||
|
@ -76,7 +73,7 @@ const hide = async () => {
|
|||
class="ui negative message"
|
||||
>
|
||||
<h4 class="header">
|
||||
Error while creating filter
|
||||
{{ $t('components.moderation.FilterModal.filterCreateFailureHeader') }}
|
||||
</h4>
|
||||
<ul class="list">
|
||||
<li
|
||||
|
@ -89,37 +86,37 @@ const hide = async () => {
|
|||
</div>
|
||||
<template v-if="type === 'artist'">
|
||||
<p>
|
||||
You will not see tracks, albums and user activity linked to this artist any more:
|
||||
{{ $t('components.moderation.FilterModal.filterCreateWarning') }}
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
In other users favorites and listening history
|
||||
{{ $t('components.moderation.FilterModal.filterWarningList1') }}
|
||||
</li>
|
||||
<li>
|
||||
In "Recently added" widget
|
||||
{{ $t('components.moderation.FilterModal.filterWarningList2') }}
|
||||
</li>
|
||||
<li>
|
||||
In artists and album listings
|
||||
{{ $t('components.moderation.FilterModal.filterWarningList3') }}
|
||||
</li>
|
||||
<li>
|
||||
In radio suggestions
|
||||
{{ $t('components.moderation.FilterModal.filterWarningList4') }}
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
You can manage and update your filters any time from your account settings.
|
||||
{{ $t('components.moderation.FilterModal.filterCreateHelp') }}
|
||||
</p>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="ui basic cancel button">
|
||||
Cancel
|
||||
{{ $t('components.moderation.FilterModal.cancelButton') }}
|
||||
</button>
|
||||
<button
|
||||
:class="['ui', 'success', {loading: isLoading}, 'button']"
|
||||
@click="hide"
|
||||
>
|
||||
Hide content
|
||||
{{ $t('components.moderation.FilterModal.hideContentButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</semantic-modal>
|
||||
|
|
|
@ -35,7 +35,7 @@ const sharedChoices = sharedLabels.fields.report_type.choices
|
|||
const allCategories = computed(() => {
|
||||
const res = []
|
||||
if (props.all) {
|
||||
res.push({ value: '', label: t('All') })
|
||||
res.push({ value: '', label: t('components.moderation.ReportCategoryDropdown.allOption') })
|
||||
}
|
||||
|
||||
const choices = props.restrictTo.length === 0
|
||||
|
@ -59,7 +59,7 @@ const allCategories = computed(() => {
|
|||
|
||||
<template>
|
||||
<div>
|
||||
<label v-if="label">Category</label>
|
||||
<label v-if="label">{{ $t('components.moderation.ReportCategoryDropdown.categoryLabel') }}</label>
|
||||
<select
|
||||
v-model="value"
|
||||
class="ui dropdown"
|
||||
|
|
|
@ -84,7 +84,7 @@ const submit = async () => {
|
|||
|
||||
store.commit('moderation/contentFilter', response.data)
|
||||
store.commit('ui/addMessage', {
|
||||
content: t('Report successfully submitted, thank you'),
|
||||
content: t('components.moderation.ReportModal.reportSubmitSuccessMessage'),
|
||||
date: new Date()
|
||||
})
|
||||
|
||||
|
@ -110,7 +110,7 @@ watchEffect(async () => {
|
|||
reportTypes.value = response.data.metadata.reportTypes ?? []
|
||||
} catch (error) {
|
||||
store.commit('ui/addMessage', {
|
||||
content: t('Cannot fetch Node Info: %{ error }', { error: `${error}` }),
|
||||
content: t('components.moderation.ReportModal.nodeinfoFetchFailure', { error: `${error}` }),
|
||||
date: new Date()
|
||||
})
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ watchEffect(async () => {
|
|||
v-if="target"
|
||||
class="ui header"
|
||||
>
|
||||
Do you want to report this object?
|
||||
{{ $t('components.moderation.ReportModal.reportModalHeader') }}
|
||||
<div class="ui sub header">
|
||||
{{ target.typeLabel }} - {{ target.label }}
|
||||
</div>
|
||||
|
@ -138,7 +138,7 @@ watchEffect(async () => {
|
|||
class="ui negative message"
|
||||
>
|
||||
<h4 class="header">
|
||||
Error while submitting report
|
||||
{{ $t('components.moderation.ReportModal.submissionFailureHeader') }}
|
||||
</h4>
|
||||
<ul class="list">
|
||||
<li
|
||||
|
@ -151,7 +151,7 @@ watchEffect(async () => {
|
|||
</div>
|
||||
</div>
|
||||
<p>
|
||||
Use this form to submit a report to our moderation team.
|
||||
{{ $t('components.moderation.ReportModal.reportModalDescription') }}
|
||||
</p>
|
||||
<form
|
||||
v-if="canSubmit"
|
||||
|
@ -173,7 +173,7 @@ watchEffect(async () => {
|
|||
class="ui eight wide required field"
|
||||
>
|
||||
<label for="report-submitter-email">
|
||||
Email
|
||||
{{ $t('components.moderation.ReportModal.emailLabel') }}
|
||||
</label>
|
||||
<input
|
||||
id="report-submitter-email"
|
||||
|
@ -183,16 +183,16 @@ watchEffect(async () => {
|
|||
required
|
||||
>
|
||||
<p>
|
||||
We'll use this e-mail address if we need to contact you regarding this report.
|
||||
{{ $t('components.moderation.ReportModal.emailDescription') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<label for="report-summary">
|
||||
Message
|
||||
{{ $t('components.moderation.ReportModal.messageLabel') }}
|
||||
</label>
|
||||
<p>
|
||||
Use this field to provide additional context to the moderator that will handle your report.
|
||||
{{ $t('components.moderation.ReportModal.messageDescription') }}
|
||||
</p>
|
||||
<content-form
|
||||
v-model="summary"
|
||||
|
@ -212,12 +212,10 @@ watchEffect(async () => {
|
|||
>
|
||||
<label for="report-forward">
|
||||
<strong>
|
||||
<translate
|
||||
:translate-params="{domain: targetDomain}"
|
||||
>Forward to %{ domain} </translate>
|
||||
{{ $t('components.moderation.ReportModal.forwardToDomainLabel', {domain: targetDomain}) }}
|
||||
</strong>
|
||||
<p>
|
||||
Forward an anonymized copy of your report to the server hosting this element.
|
||||
{{ $t('components.moderation.ReportModal.forwardToDomainDescription') }}
|
||||
</p>
|
||||
</label>
|
||||
</div>
|
||||
|
@ -234,13 +232,13 @@ watchEffect(async () => {
|
|||
class="ui warning message"
|
||||
>
|
||||
<h4 class="header">
|
||||
Anonymous reports are disabled, please sign-in to submit a report.
|
||||
{{ $t('components.moderation.ReportModal.anonymousReportsDisabled') }}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="ui basic cancel button">
|
||||
Cancel
|
||||
{{ $t('components.moderation.ReportModal.cancelButton') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="canSubmit"
|
||||
|
@ -248,7 +246,7 @@ watchEffect(async () => {
|
|||
type="submit"
|
||||
form="report-form"
|
||||
>
|
||||
Submit report
|
||||
{{ $t('components.moderation.ReportModal.submitReportButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</semantic-modal>
|
||||
|
|
|
@ -17,12 +17,8 @@ const { t } = useI18n()
|
|||
const store = useStore()
|
||||
|
||||
const labels = computed(() => ({
|
||||
libraryFollowMessage: t('%{ username } followed your library "%{ library }"'),
|
||||
libraryAcceptFollowMessage: t('%{ username } accepted your follow on library "%{ library }"'),
|
||||
libraryRejectMessage: t('You rejected %{ username }'s request to follow "%{ library }"'),
|
||||
libraryPendingFollowMessage: t('%{ username } wants to follow your library "%{ library }"'),
|
||||
markRead: t('Mark as read'),
|
||||
markUnread: t('Mark as unread')
|
||||
markRead: t('components.notifications.NotificationRow.markRead'),
|
||||
markUnread: t('components.notifications.NotificationRow.markUnread')
|
||||
}))
|
||||
|
||||
const item = ref(props.initialItem)
|
||||
|
@ -39,30 +35,30 @@ const notificationData = computed(() => {
|
|||
if (activity.related_object?.approved === null) {
|
||||
return {
|
||||
detailUrl,
|
||||
message: t(labels.value.libraryPendingFollowMessage, { username: username.value, library: activity.object.name }),
|
||||
message: t('components.notifications.NotificationRow.libraryPendingFollowMessage', { username: username.value, library: activity.object.name }),
|
||||
acceptFollow: {
|
||||
buttonClass: 'success',
|
||||
icon: 'check',
|
||||
label: t('Approve'),
|
||||
label: t('components.notifications.NotificationRow.approve'),
|
||||
handler: () => approveLibraryFollow(activity.related_object)
|
||||
},
|
||||
rejectFollow: {
|
||||
buttonClass: 'danger',
|
||||
icon: 'x',
|
||||
label: t('Reject'),
|
||||
label: t('components.notifications.NotificationRow.reject'),
|
||||
handler: () => rejectLibraryFollow(activity.related_object)
|
||||
}
|
||||
}
|
||||
} else if (activity.related_object?.approved) {
|
||||
return {
|
||||
detailUrl,
|
||||
message: t(labels.value.libraryFollowMessage, { username: username.value, library: activity.object.name })
|
||||
message: t('components.notifications.NotificationRow.libraryFollowMessage', { username: username.value, library: activity.object.name })
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
detailUrl,
|
||||
message: t(labels.value.libraryRejectMessage, { username: username.value, library: activity.object.name })
|
||||
message: t('components.notifications.NotificationRow.libraryRejectMessage', { username: username.value, library: activity.object.name })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +67,7 @@ const notificationData = computed(() => {
|
|||
if (activity.object?.type === 'federation.LibraryFollow') {
|
||||
return {
|
||||
detailUrl: { name: 'content.remote.index' },
|
||||
message: t(labels.value.libraryAcceptFollowMessage, { username: username.value, library: activity.related_object.name })
|
||||
message: t('components.notifications.NotificationRow.libraryAcceptFollowMessage', { username: username.value, library: activity.related_object.name })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,14 +61,7 @@ const images = computed(() => {
|
|||
</div>
|
||||
</div>
|
||||
<div class="extra content">
|
||||
<translate
|
||||
|
||||
:translate-params="{count: playlist.tracks_count}"
|
||||
:translate-n="playlist.tracks_count"
|
||||
translate-plural="%{ count } tracks"
|
||||
>
|
||||
%{ count } track
|
||||
</translate>
|
||||
{{ $t('components.playlists.Card.trackCount', {tracks_count: playlist.tracks_count}) }}
|
||||
<play-button
|
||||
class="right floated basic icon"
|
||||
:dropdown-only="true"
|
||||
|
|
|
@ -51,7 +51,7 @@ const tracks = computed({
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
copyTitle: t('Copy the current queue to this playlist')
|
||||
copyTitle: t('components.playlists.Editor.copyTitle')
|
||||
}))
|
||||
|
||||
const isLoading = ref(false)
|
||||
|
@ -167,16 +167,16 @@ const insertMany = async (insertedTracks: number[], allowDuplicates: boolean) =>
|
|||
:title="undefined"
|
||||
/>
|
||||
<h3 class="ui top attached header">
|
||||
Playlist editor
|
||||
{{ $t('components.playlists.Editor.editorHeader') }}
|
||||
</h3>
|
||||
<div class="ui attached segment">
|
||||
<template v-if="status === 'loading'">
|
||||
<div class="ui active tiny inline loader" />
|
||||
Syncing changes to server…
|
||||
{{ $t('components.playlists.Editor.syncingChangesMessage') }}
|
||||
</template>
|
||||
<template v-else-if="status === 'errored'">
|
||||
<i class="dangerclose icon" />
|
||||
An error occurred while saving your changes
|
||||
{{ $t('components.playlists.Editor.syncingChangesFailureMessage') }}
|
||||
<div
|
||||
v-if="errors.length > 0"
|
||||
role="alert"
|
||||
|
@ -197,10 +197,8 @@ const insertMany = async (insertedTracks: number[], allowDuplicates: boolean) =>
|
|||
role="alert"
|
||||
class="ui warning message"
|
||||
>
|
||||
<p
|
||||
v-translate="{playlist: playlist?.name}"
|
||||
>
|
||||
Some tracks in your queue are already in this playlist:
|
||||
<p>
|
||||
{{ $t('components.playlists.Editor.tracksExistWarning') }}
|
||||
</p>
|
||||
<ul class="ui relaxed divided list duplicate-tracks-list">
|
||||
<li
|
||||
|
@ -215,11 +213,12 @@ const insertMany = async (insertedTracks: number[], allowDuplicates: boolean) =>
|
|||
class="ui small success button"
|
||||
@click="insertMany(queueTracks, true)"
|
||||
>
|
||||
Add anyways
|
||||
{{ $t('components.playlists.Editor.addAnywayButton') }}
|
||||
</button>
|
||||
</div>
|
||||
<template v-else-if="status === 'saved'">
|
||||
<i class="success check icon" /> Changes synced with server
|
||||
<i class="success check icon" />
|
||||
{{ $t('components.playlists.Editor.syncedStatus') }}
|
||||
</template>
|
||||
</div>
|
||||
<div class="ui bottom attached segment">
|
||||
|
@ -230,14 +229,7 @@ const insertMany = async (insertedTracks: number[], allowDuplicates: boolean) =>
|
|||
@click="insertMany(queueTracks, false)"
|
||||
>
|
||||
<i class="plus icon" />
|
||||
<translate
|
||||
|
||||
translate-plural="Insert from queue (%{ count } tracks)"
|
||||
:translate-n="queueTracks.length"
|
||||
:translate-params="{count: queueTracks.length}"
|
||||
>
|
||||
Insert from queue (%{ count } track)
|
||||
</translate>
|
||||
{{ $t('components.playlists.Editor.insertCount', {count: queueTracks.length}) }}
|
||||
</button>
|
||||
|
||||
<dangerous-button
|
||||
|
@ -245,31 +237,28 @@ const insertMany = async (insertedTracks: number[], allowDuplicates: boolean) =>
|
|||
class="ui labeled right floated danger icon button"
|
||||
:action="clearPlaylist"
|
||||
>
|
||||
<i class="eraser icon" /> Clear playlist
|
||||
<i class="eraser icon" />
|
||||
{{ $t('components.playlists.Editor.clearPlaylistButton') }}
|
||||
<template #modal-header>
|
||||
<p
|
||||
v-translate="{playlist: playlist?.name}"
|
||||
|
||||
:translate-params="{playlist: playlist?.name}"
|
||||
>
|
||||
Do you want to clear the playlist "%{ playlist }"?
|
||||
<p>
|
||||
{{ $t('components.playlists.Editor.clearPlaylistModalHeader', {playlist: playlist?.name}) }}
|
||||
</p>
|
||||
</template>
|
||||
<template #modal-content>
|
||||
<p>
|
||||
This will remove all tracks from this playlist and cannot be undone.
|
||||
{{ $t('components.playlists.Editor.clearPlaylistModalContent') }}
|
||||
</p>
|
||||
</template>
|
||||
<template #modal-confirm>
|
||||
<div>
|
||||
Clear playlist
|
||||
{{ $t('components.playlists.Editor.clearPlaylistButton') }}
|
||||
</div>
|
||||
</template>
|
||||
</dangerous-button>
|
||||
<div class="ui hidden divider" />
|
||||
<template v-if="tracks.length > 0">
|
||||
<p>
|
||||
Drag and drop rows to reorder tracks in the playlist
|
||||
{{ $t('components.playlists.Editor.reorderTracks') }}
|
||||
</p>
|
||||
<div class="table-wrapper">
|
||||
<table class="ui compact very basic unstackable table">
|
||||
|
|
|
@ -42,7 +42,7 @@ const privacyLevel = ref(playlist.value?.privacy_level ?? store.state.auth.profi
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
placeholder: t('My awesome playlist')
|
||||
placeholder: t('components.playlists.Form.placeholder')
|
||||
}))
|
||||
|
||||
const sharedLabels = useSharedLabels()
|
||||
|
@ -111,7 +111,7 @@ const submit = async () => {
|
|||
v-if="title"
|
||||
class="ui header"
|
||||
>
|
||||
Create a new playlist
|
||||
{{ $t('components.playlists.Form.createPlaylistHeader') }}
|
||||
</h4>
|
||||
<div
|
||||
v-if="success"
|
||||
|
@ -119,10 +119,10 @@ const submit = async () => {
|
|||
>
|
||||
<h4 class="header">
|
||||
<template v-if="playlist">
|
||||
Playlist updated
|
||||
{{ $t('components.playlists.Form.updateSuccessHeader') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
Playlist created
|
||||
{{ $t('components.playlists.Form.createSuccessHeader') }}
|
||||
</template>
|
||||
</h4>
|
||||
</div>
|
||||
|
@ -132,7 +132,7 @@ const submit = async () => {
|
|||
class="ui negative message"
|
||||
>
|
||||
<h4 class="header">
|
||||
The playlist could not be created
|
||||
{{ $t('components.playlists.Form.createFailureHeader') }}
|
||||
</h4>
|
||||
<ul class="list">
|
||||
<li
|
||||
|
@ -145,7 +145,7 @@ const submit = async () => {
|
|||
</div>
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label for="playlist-name">Playlist name</label>
|
||||
<label for="playlist-name">{{ $t('components.playlists.Form.playlistNameLabel') }}</label>
|
||||
<input
|
||||
id="playlist-name"
|
||||
v-model="name"
|
||||
|
@ -156,7 +156,7 @@ const submit = async () => {
|
|||
>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="playlist-visibility">Playlist visibility</label>
|
||||
<label for="playlist-visibility">{{ $t('components.playlists.Form.playlistVisibilityLabel') }}</label>
|
||||
<select
|
||||
id="playlist-visibility"
|
||||
v-model="privacyLevel"
|
||||
|
@ -178,10 +178,10 @@ const submit = async () => {
|
|||
type="submit"
|
||||
>
|
||||
<template v-if="playlist">
|
||||
Update playlist
|
||||
{{ $t('components.playlists.Form.updatePlaylistButton') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
Create playlist
|
||||
{{ $t('components.playlists.Form.createPlaylistButton') }}
|
||||
</template>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -27,8 +27,8 @@ const track = computed(() => store.state.playlists.modalTrack)
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
addToPlaylist: t('Add to this playlist'),
|
||||
filterPlaylistField: t('Enter playlist name')
|
||||
addToPlaylist: t('components.playlists.PlaylistModal.addToPlaylist'),
|
||||
filterPlaylistField: t('components.playlists.PlaylistModal.filterPlaylistField')
|
||||
}))
|
||||
|
||||
const playlistNameFilter = ref('')
|
||||
|
@ -85,21 +85,18 @@ store.dispatch('playlists/fetchOwn')
|
|||
<h4 class="header">
|
||||
<template v-if="track">
|
||||
<h2 class="ui header">
|
||||
Add to playlist
|
||||
{{ $t('components.playlists.PlaylistModal.addToPlaylistHeader') }}
|
||||
<div
|
||||
v-translate="{artist: track.artist?.name, title: track.title}"
|
||||
class="ui sub header"
|
||||
|
||||
:translate-params="{artist: track.artist?.name, title: track.title}"
|
||||
>
|
||||
"%{ title }", by %{ artist }
|
||||
{{ $t('components.playlists.PlaylistModal.trackTitle', {artist: track.artist?.name, title: track.title}) }}
|
||||
</div>
|
||||
</h2>
|
||||
</template>
|
||||
<translate
|
||||
v-else
|
||||
>
|
||||
Manage playlists
|
||||
{{ $t('components.playlists.PlaylistModal.managePlaylistsHeader') }}
|
||||
</translate>
|
||||
</h4>
|
||||
<div class="scrolling content">
|
||||
|
@ -114,24 +111,20 @@ store.dispatch('playlists/fetchOwn')
|
|||
role="alert"
|
||||
class="ui warning message"
|
||||
>
|
||||
<p
|
||||
v-translate="{track: track?.title, playlist: duplicateTrackAddInfo.playlist_name}"
|
||||
|
||||
:translate-params="{track: track?.title, playlist: duplicateTrackAddInfo.playlist_name}"
|
||||
>
|
||||
<strong>%{ track }</strong> is already in <strong>%{ playlist }</strong>.
|
||||
<p>
|
||||
{{ $t('components.playlists.PlaylistModal.trackAlreadyInPlaylist', {track: track?.title, playlist: duplicateTrackAddInfo.playlist_name}) }}
|
||||
</p>
|
||||
<button
|
||||
class="ui small basic cancel button"
|
||||
@click="showDuplicateTrackAddConfirmation = false"
|
||||
>
|
||||
Cancel
|
||||
{{ $t('components.playlists.PlaylistModal.cancelButton') }}
|
||||
</button>
|
||||
<button
|
||||
class="ui small success button"
|
||||
@click="addToPlaylist(lastSelectedPlaylist, true)"
|
||||
>
|
||||
Add anyways
|
||||
{{ $t('components.playlists.PlaylistModal.addAnywayButton') }}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
|
@ -140,7 +133,7 @@ store.dispatch('playlists/fetchOwn')
|
|||
class="ui negative message"
|
||||
>
|
||||
<h4 class="header">
|
||||
The track can't be added to a playlist
|
||||
{{ $t('components.playlists.PlaylistModal.trackAddFailureHeader') }}
|
||||
</h4>
|
||||
<ul class="list">
|
||||
<li
|
||||
|
@ -152,12 +145,12 @@ store.dispatch('playlists/fetchOwn')
|
|||
</ul>
|
||||
</div>
|
||||
<h4 class="ui header">
|
||||
Available playlists
|
||||
{{ $t('components.playlists.PlaylistModal.availablePlaylistsHeader') }}
|
||||
</h4>
|
||||
<div class="ui form">
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
<label for="playlist-name-filter">Filter</label>
|
||||
<label for="playlist-name-filter">{{ $t('components.playlists.PlaylistModal.filterLabel') }}</label>
|
||||
<input
|
||||
id="playlist-name-filter"
|
||||
v-model="playlistNameFilter"
|
||||
|
@ -174,15 +167,15 @@ store.dispatch('playlists/fetchOwn')
|
|||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><span class="visually-hidden">Edit</span></th>
|
||||
<th><span class="visually-hidden">{{ $t('components.playlists.PlaylistModal.editTableHeader') }}</span></th>
|
||||
<th>
|
||||
Name
|
||||
{{ $t('components.playlists.PlaylistModal.nameTableHeader') }}
|
||||
</th>
|
||||
<th class="sorted descending">
|
||||
Last modification
|
||||
{{ $t('components.playlists.PlaylistModal.lastModificationTableHeader') }}
|
||||
</th>
|
||||
<th>
|
||||
Tracks
|
||||
{{ $t('components.playlists.PlaylistModal.tracksTableHeader') }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@ -197,7 +190,7 @@ store.dispatch('playlists/fetchOwn')
|
|||
:to="{name: 'library.playlists.detail', params: {id: playlist.id }, query: {mode: 'edit'}}"
|
||||
>
|
||||
<i class="ui pencil icon" />
|
||||
<span class="visually-hidden">Edit</span>
|
||||
<span class="visually-hidden">{{ $t('components.playlists.PlaylistModal.editTableHeader') }}</span>
|
||||
</router-link>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -217,7 +210,8 @@ store.dispatch('playlists/fetchOwn')
|
|||
:title="labels.addToPlaylist"
|
||||
@click.prevent="addToPlaylist(playlist.id, false)"
|
||||
>
|
||||
<i class="plus icon" /> Add track
|
||||
<i class="plus icon" />
|
||||
{{ $t('components.playlists.PlaylistModal.addTrackButton') }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -226,7 +220,7 @@ store.dispatch('playlists/fetchOwn')
|
|||
<template v-else>
|
||||
<div class="ui small placeholder segment component-placeholder">
|
||||
<h4 class="ui header">
|
||||
No results matching your filter
|
||||
{{ $t('components.playlists.PlaylistModal.emptyStateMessage') }}
|
||||
</h4>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -237,13 +231,13 @@ store.dispatch('playlists/fetchOwn')
|
|||
>
|
||||
<div class="ui icon header">
|
||||
<i class="list icon" />
|
||||
No playlists have been created yet
|
||||
{{ $t('components.playlists.PlaylistModal.noPlaylistsMessage') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="ui basic cancel button">
|
||||
Cancel
|
||||
{{ $t('components.playlists.PlaylistModal.cancelButton') }}
|
||||
</button>
|
||||
</div>
|
||||
</semantic-modal>
|
||||
|
|
|
@ -20,7 +20,7 @@ withDefaults(defineProps<Props>(), {
|
|||
const { t } = useI18n()
|
||||
|
||||
const labels = computed(() => ({
|
||||
addToPlaylist: t('Add to playlist…')
|
||||
addToPlaylist: t('components.playlists.TrackPlaylistIcon.addToPlaylist')
|
||||
}))
|
||||
</script>
|
||||
|
||||
|
@ -31,7 +31,7 @@ const labels = computed(() => ({
|
|||
@click.stop="$store.commit('playlists/chooseTrack', track)"
|
||||
>
|
||||
<i class="list icon" />
|
||||
Add to playlist…
|
||||
{{ $t('components.playlists.TrackPlaylistIcon.addToPlaylist') }}
|
||||
</button>
|
||||
<button
|
||||
v-else
|
||||
|
|
|
@ -78,7 +78,7 @@ watch(
|
|||
>
|
||||
<div class="ui icon header">
|
||||
<i class="list icon" />
|
||||
No playlists have been created yet
|
||||
{{ $t('components.playlists.Widget.noPlaylistsMessage') }}
|
||||
</div>
|
||||
<button
|
||||
v-if="$store.state.auth.authenticated"
|
||||
|
@ -86,7 +86,7 @@ watch(
|
|||
@click="$store.commit('playlists/chooseTrack', null)"
|
||||
>
|
||||
<i class="list icon" />
|
||||
Create Playlist
|
||||
{{ $t('components.playlists.Widget.createPlaylistButton') }}
|
||||
</button>
|
||||
</div>
|
||||
<template v-if="nextPage">
|
||||
|
@ -96,7 +96,7 @@ watch(
|
|||
:class="['ui', 'basic', 'button']"
|
||||
@click="fetchData(nextPage)"
|
||||
>
|
||||
Show more
|
||||
{{ $t('components.playlists.Widget.showMore') }}
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
|
|
|
@ -41,20 +41,20 @@ const buttonLabel = computed(() => {
|
|||
switch (props.radioConfig?.type) {
|
||||
case 'tag':
|
||||
return running.value
|
||||
? t('Stop tags radio')
|
||||
: t('Start tags radio')
|
||||
? t('components.radios.Button.stopTagsRadio')
|
||||
: t('components.radios.Button.startTagsRadio')
|
||||
case 'artist':
|
||||
return running.value
|
||||
? t('Stop artists radio')
|
||||
: t('Start artists radio')
|
||||
? t('components.radios.Button.stopArtistsRadio')
|
||||
: t('components.radios.Button.startArtistsRadio')
|
||||
case 'playlist':
|
||||
return running.value
|
||||
? t('Stop playlists radio')
|
||||
: t('Start playlists radio')
|
||||
? t('components.radios.Button.stopPlaylistsRadio')
|
||||
: t('components.radios.Button.startPlaylistsRadio')
|
||||
default:
|
||||
return running.value
|
||||
? t('Stop radio')
|
||||
: t('Play radio')
|
||||
? t('components.radios.Button.stopRadio')
|
||||
: t('components.radios.Button.startRadio')
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ const customRadioId = computed(() => props.customRadio?.id ?? null)
|
|||
class="ui success button right floated"
|
||||
:to="{name: 'library.radios.edit', params: {id: customRadioId }}"
|
||||
>
|
||||
Edit
|
||||
{{ $t('components.radios.Card.editButton') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -46,14 +46,7 @@ const tags = computed(() => {
|
|||
class="ui circular inverted accent label"
|
||||
@click.prevent="honorLimit = false"
|
||||
>
|
||||
<translate
|
||||
|
||||
:translate-params="{ count: props.tags.length - tags.length }"
|
||||
:translate-n="props.tags.length - tags.length"
|
||||
translate-plural="Show %{ count } more tags"
|
||||
>
|
||||
Show 1 more tag
|
||||
</translate>
|
||||
{{ $t('components.tags.List.showMoreTags', {count: props.tags.length - tags.length}) }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -63,9 +63,9 @@ const setPage = (page: number) => {
|
|||
|
||||
const { t } = useI18n()
|
||||
const labels = computed(() => ({
|
||||
pagination: t('Pagination'),
|
||||
previousPage: t('Previous Page'),
|
||||
nextPage: t('Next Page')
|
||||
pagination: t('components.vui.Pagination.pagination'),
|
||||
previousPage: t('components.vui.Pagination.previousPage'),
|
||||
nextPage: t('components.vui.Pagination.nextPage')
|
||||
}))
|
||||
</script>
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue