fix(front): translations

environments/review-docs-feat-z0hkbz/deployments/20994
jon r 2025-04-03 12:49:38 +02:00
rodzic 02daeab46e
commit 60f38a3117
20 zmienionych plików z 69 dodań i 138 usunięć

Wyświetl plik

@ -1,105 +0,0 @@
<script setup lang="ts">
import { useIntervalFn, useStyleTag, useToggle, useWindowSize } from '@vueuse/core'
import { computed, defineAsyncComponent, nextTick, onMounted } from 'vue'
import { useQueue } from '~/composables/audio/queue'
import { useStore } from '~/store'
import { useI18n } from 'vue-i18n'
import onKeyboardShortcut from '~/composables/onKeyboardShortcut'
const { t } = useI18n()
const ChannelUploadModal = defineAsyncComponent(() => import('~/components/channels/UploadModal.vue'))
const PlaylistModal = defineAsyncComponent(() => import('~/components/playlists/PlaylistModal.vue'))
const FilterModal = defineAsyncComponent(() => import('~/components/moderation/FilterModal.vue'))
const ReportModal = defineAsyncComponent(() => import('~/components/moderation/ReportModal.vue'))
const ServiceMessages = defineAsyncComponent(() => import('~/components/ServiceMessages.vue'))
const ShortcutsModal = defineAsyncComponent(() => import('~/components/ShortcutsModal.vue'))
const AudioPlayer = defineAsyncComponent(() => import('~/components/audio/Player.vue'))
const Sidebar = defineAsyncComponent(() => import('~/components/Sidebar.vue'))
const Queue = defineAsyncComponent(() => import('~/components/Queue.vue'))
const store = useStore()
// Tracks
const { tracks } = useQueue()
// Fake content
onMounted(async () => {
await nextTick()
document.getElementById('fake-content')?.classList.add('loaded')
})
// Styles
const customStylesheets = computed(() => {
return store.state.instance.frontSettings.additionalStylesheets ?? []
})
useStyleTag(computed(() => store.state.instance.settings.ui.custom_css.value))
// Time ago
useIntervalFn(() => {
// used to redraw ago dates every minute
store.commit('ui/computeLastDate')
}, 1000 * 60)
// Shortcuts
const [showShortcutsModal, toggleShortcutsModal] = useToggle(false)
onKeyboardShortcut('h', () => toggleShortcutsModal())
const { width } = useWindowSize()
</script>
<template>
<div
:key="store.state.instance.instanceUrl"
:class="{
'has-bottom-player': tracks.length > 0,
'queue-focused': store.state.ui.queueFocused
}"
>
<!-- here, we display custom stylesheets, if any -->
<link
v-for="url in customStylesheets"
:key="url"
rel="stylesheet"
property="stylesheet"
:href="url"
>
<sidebar
:width="width"
@show:shortcuts-modal="toggleShortcutsModal"
/>
<service-messages />
<transition name="queue">
<queue v-show="store.state.ui.queueFocused" />
</transition>
<router-view v-slot="{ Component }">
<template v-if="Component">
<keep-alive :max="1">
<Suspense>
<component :is="Component" />
<template #fallback>
<!-- TODO (wvffle): Add loader -->
{{ t('App.loading') }}
</template>
</Suspense>
</keep-alive>
</template>
<template v-else>
<!-- Display a proper 404 page or error message -->
<h1>404 - Page Not Found</h1>
</template>
</router-view>
<audio-player />
<playlist-modal v-if="store.state.auth.authenticated" />
<channel-upload-modal v-if="store.state.auth.authenticated" />
<filter-modal v-if="store.state.auth.authenticated" />
<report-modal />
<shortcuts-modal v-model:show="showShortcutsModal" />
</div>
</template>

Wyświetl plik

@ -7,6 +7,8 @@ import { ref, computed, watch, nextTick } from 'vue'
import { useStore } from '~/store'
import { useI18n } from 'vue-i18n'
// TODO: Delete this file?
const { t } = useI18n()
interface Props {
@ -65,6 +67,7 @@ const checkAndSwitch = async (url: string) => {
</script>
<template>
<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
<Modal
v-model="show"
:title="t('views.ChooseInstance.header.chooseInstance')"
@ -181,4 +184,5 @@ const checkAndSwitch = async (url: string) => {
</button>
</div>
</Modal>
<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
</template>

Wyświetl plik

@ -250,8 +250,7 @@ const save = async () => {
red
>
<h4 class="header">
{{ group.label }}:
{{ t('components.admin.SettingsGroup.header.error') }}
{{ t('components.admin.SettingsGroup.header.error', {label: group.label}) }}
</h4>
<ul class="list">
<li

Wyświetl plik

@ -71,7 +71,7 @@ watch(albums, (value) => {
icon="bi-plus"
:to="useModal('album').to"
>
Add Album
{{ t('components.channels.AlbumSelect.add') }}
<AlbumModal
v-model="model.channel"
@created="fetchAlbums"

Wyświetl plik

@ -6,6 +6,7 @@ import { computed, reactive, ref } from 'vue'
import { isEqual, clone } from 'lodash-es'
import { useI18n } from 'vue-i18n'
import { useStore } from '~/store'
import { useRoute } from 'vue-router'
import axios from 'axios'
@ -36,6 +37,7 @@ const props = withDefaults(defineProps<Props>(), {
const { t } = useI18n()
const configs = useEditConfigs()
const store = useStore()
const route = useRoute()
const config = computed(() => configs[props.objectType])
const currentState = computed(() => config.value.fields.reduce((state: ReviewState, field) => {
@ -157,13 +159,15 @@ const resetField = (fieldId: string) => {
{{ t('components.library.EditForm.button.new') }}
</Button>
<!-- TODO: Implement link back to all types of object -->
<Link
v-if="route.path.includes('album')"
solid
secondary
raised
:to="{ name: 'library.albums.detail', params: { id: object.id } }"
>
Back to Album
{{ t('components.library.EditForm.button.backToAlbum') }}
</Link>
</Alert>
<Layout

Wyświetl plik

@ -426,7 +426,7 @@ const isServerDisclosureOpen = ref(false)
'yellow': files.length > uploadedFilesCount + erroredFilesCount
}"
>
{{ uploadedFilesCount + erroredFilesCount }} / {{ files.length }}
{{ t('components.library.FileUpload.table.upload.progressNum', {current: uploadedFilesCount + erroredFilesCount, total: files.length}) }}
</Pill>
</Layout>
<Layout
@ -435,7 +435,7 @@ const isServerDisclosureOpen = ref(false)
>
<label>{{ t('components.library.FileUpload.link.processing') }}</label>
<Pill>
{{ processedFilesCount }} / {{ processableFiles }}
{{ t('components.library.FileUpload.table.upload.progressNum', {current: processedFilesCount, total: processableFiles}) }}
</Pill>
</Layout>
</Layout>

Wyświetl plik

@ -330,7 +330,7 @@
"save": "Save"
},
"header": {
"error": "Error while saving settings.",
"error": "{label}: Error while saving settings.",
"image": "Current image"
},
"message": {
@ -1027,6 +1027,7 @@
}
},
"AlbumSelect": {
"add": "Add Album",
"label": {
"album": "Album",
"series": "Series"
@ -1642,6 +1643,7 @@
},
"EditForm": {
"button": {
"backToAlbum": "Back to Album",
"cancel": "Cancel",
"clear": "Clear",
"new": "Submit another edit",
@ -1716,6 +1718,7 @@
"size": "Size",
"status": "Status"
},
"progressNum": "{current} / {total}",
"progress": "{percent}%",
"status": {
"pending": "Pending",
@ -3253,6 +3256,16 @@
"newAppVersion": "A new version of the app is available."
}
},
"modals": {
"search": {
"tryAgain": "If the following link does not work, wait a few seconds and try again"
},
"upload": {
"library": "Host music you listen to",
"musicChannel": "Publish music you make",
"podcastChannel": "Publish podcasts you make"
}
},
"views": {
"ChooseInstance": {
"button": {
@ -4371,7 +4384,7 @@
"currentUsage": "Current usage"
},
"label": {
"currentUsage": "{amount} used on {max} allowed",
"currentUsage": "{currentAmount} used on {max} allowed",
"errored": "Errored files",
"pending": "Pending files",
"percentUsed": "{progress}%",
@ -4583,7 +4596,9 @@
"tracks": "Tracks"
},
"meta": {
"tracks": "Playlist containing {n} track, by {username} | Playlist containing {n} tracks, by {username}"
"attribution": "by",
"tracks": "Playlist containing {n} track, by {username} | Playlist containing {n} tracks, by {username}",
"updated": "updated"
},
"modal": {
"delete": {

Wyświetl plik

@ -355,19 +355,6 @@ const moderationNotifications = computed(() =>
{{ t('components.Sidebar.link.about') }}
</Link>
<Spacer shrink />
<Link
thin-font
to="/privacy"
>
Privacy
</Link>
<Spacer shrink />
<Link
thin-font
to="/legal"
>
Legal
</Link>
</Layout>
</Layout>
</Layout>

Wyświetl plik

@ -6,6 +6,8 @@ import UploadList from '~/ui/components/UploadList.vue'
import { UseTimeAgo } from '@vueuse/components'
import { Icon } from '@iconify/vue'
// TODO: Delete this file, please.
defineProps<{ groups: UploadGroup[], isUploading?: boolean }>()
const openUploadGroup = ref<UploadGroup>()
@ -45,6 +47,7 @@ const getDescription = (group: UploadGroup) => {
</script>
<template>
<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
<div>
<div
v-for="group of groups"
@ -161,6 +164,7 @@ const getDescription = (group: UploadGroup) => {
</VerticalCollapse>
</div>
</div>
<!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
</template>
<style scoped lang="scss">

Wyświetl plik

@ -10,9 +10,12 @@ defineProps<{
wide?: boolean
}>()
// TODO: Delete this file, please.
</script>
<template>
<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
<div class="file-list">
<div
v-for="track in uploads"
@ -106,6 +109,7 @@ defineProps<{
/>
</div>
</div>
<!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
</template>
<style scoped lang="scss">

Wyświetl plik

@ -63,7 +63,7 @@ const continueInBackground = () => {
return router.push('/upload/running')
}
// TODO (whole file): Translations
// TODO (whole file): Delete this file, please.
// Sorting
const sortItems = reactive([
@ -94,6 +94,7 @@ const isOpen = computed({
</script>
<template>
<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
<Modal
v-model="isOpen"
title="Upload..."
@ -162,6 +163,7 @@ const isOpen = computed({
</Button>
</template>
</Modal>
<!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
</template>
<style scoped lang="scss">

Wyświetl plik

@ -492,7 +492,7 @@ watch(queryDebounced, search, { immediate: true })
<!-- If response has "url": "webfinger://node1@node1.funkwhale.test" -> Link to go directly to the federation page -->
<span v-if="category.type === 'rss' && count(category) > 0">
<Alert>If the following link does not work, wait a few seconds and try again</Alert>
<Alert>{{ t('modals.search.tryAgain') }}</Alert>
<Link
v-for="channel in resultsPerCategory(category)"
:key="channel.artist.fid"
@ -504,7 +504,8 @@ watch(queryDebounced, search, { immediate: true })
</span>
<span v-else-if="category.type === 'federation'">
TODO: {{ resultsPerCategory(category) }}
<!-- TODO: Federation search: backend adapter + display, fix results_per_category query -->
<!-- {{ resultsPerCategory(category) }} -->
</span>
<EmptyState

Wyświetl plik

@ -110,7 +110,7 @@ const channelUpload = ref()
:class="$style.icon"
/>
</template>
{{ "Host music you listen to" /* TODO: Translate */ }}
{{ t('modals.upload.library') }}
</Card>
<Card
small
@ -125,7 +125,7 @@ const channelUpload = ref()
:class="$style.icon"
/>
</template>
{{ "Publish music you make" /* TODO: Translate */ }}
{{ t('modals.upload.musicChannel') }}
</Card>
<Card
small
@ -140,7 +140,7 @@ const channelUpload = ref()
:class="$style.icon"
/>
</template>
{{ "Publish podcasts you make" /* TODO: Translate */ }}
{{ t('modals.upload.podcastChannel') }}
</Card>
</Layout>

Wyświetl plik

@ -4,6 +4,8 @@ import { useUploadsStore } from '~/ui/stores/upload'
import { bytesToHumanSize } from '~/ui/composables/bytes'
import UploadModal from '~/ui/components/UploadModal.vue'
// TODO: Delete this file?
const filesystemStats = reactive({
total: 10737418240,
used: 3e9
@ -40,6 +42,7 @@ const tabs = computed(() => [
</script>
<template>
<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
<div class="flex items-center">
<h1 class="mr-auto">
Upload
@ -82,6 +85,7 @@ const tabs = computed(() => [
<RouterView />
<UploadModal />
<!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
</template>
<style scoped lang="scss">

Wyświetl plik

@ -5,6 +5,8 @@ import { bytesToHumanSize } from '~/ui/composables/bytes'
import { useUploadsStore, type UploadGroupEntry } from '~/ui/stores/upload'
import CoverArt from '~/ui/components/CoverArt.vue'
// TODO: Delete this file?
interface Recording {
guid: string
title: string
@ -49,6 +51,7 @@ const columns = [
</script>
<template>
<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
<div
v-if="allTracks.length === 0"
class="flex flex-col items-center py-32"
@ -80,6 +83,7 @@ const columns = [
{{ intl.format(value) }}
</template>
</FwTable>
<!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
</template>
<style scoped>

Wyświetl plik

@ -5,6 +5,8 @@ import { ref } from 'vue'
import axios from 'axios'
import { useAsyncState } from '@vueuse/core'
// TODO: Delete this file?
interface Tab {
label: string
icon: string
@ -49,6 +51,7 @@ const { state: items } = useAsyncState(
</script>
<template>
<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
<div class="upload">
<p> Select a destination for your audio files: </p>
@ -98,6 +101,7 @@ const { state: items } = useAsyncState(
Open library
</FwButton>
</div>
<!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
</template>
<style scoped lang="scss">

Wyświetl plik

@ -22,6 +22,8 @@ import Button from '~/components/ui/Button.vue'
import useErrorHandler from '~/composables/useErrorHandler'
import useLogger from '~/composables/useLogger'
// TODO: Depreciate & refactor essential functionality to new ui/modals/Search.vue
type QueryType = 'artists' | 'albums' | 'tracks' | 'playlists' | 'tags' | 'radios' | 'podcasts' | 'series' | 'rss'
const type = useRouteQuery<QueryType>('type', 'artists')
@ -226,7 +228,6 @@ const radioConfig = computed(() => {
class="main"
>
<section class="ui vertical stripe segment">
/front/src/components/audio/Search.vue
<div
v-if="id"
class="ui small text container"

Wyświetl plik

@ -84,7 +84,7 @@ const purgeErroredFiles = () => purge('errored')
v-if="quotaStatus"
class="label"
>
{{ t('views.content.libraries.Quota.label.currentUsage', {max: humanSize(quotaStatus.max * 1000 * 1000), current: humanSize(quotaStatus.current * 1000 * 1000)}) }}
{{ t('views.content.libraries.Quota.label.currentUsage', {max: humanSize(quotaStatus.max * 1000 * 1000), currentAmount: humanSize(quotaStatus.current * 1000 * 1000)}) }}
</div>
</div>
<div class="ui hidden divider" />

Wyświetl plik

@ -21,6 +21,8 @@ import Upload from '~/ui/pages/upload.vue'
import useErrorHandler from '~/composables/useErrorHandler'
// TODO: Delete this file.
const { t } = useI18n()
const router = useRouter()
@ -103,6 +105,7 @@ const openModal = (object_: Library | Channel) => {
<template>
<!-- TODO: Remove this module -->
<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
<section
v-title="labels.title"
class="ui vertical aligned stripe segment"
@ -160,4 +163,5 @@ const openModal = (object_: Library | Channel) => {
<upload />
</fw-modal>
<!-- <channel-upload-modal v-if="store.state.auth.authenticated" /> -->
<!-- eslint-enable @intlify/vue-i18n/no-raw-text -->
</template>

Wyświetl plik

@ -162,15 +162,14 @@ const deletePlaylist = async () => {
flex
gap-8
>
<!-- TODO: Translations -->
by
{{ t('views.playlists.Detail.meta.attribution') }}
<ActorLink
:actor="playlist.actor"
:avatar="false"
:discrete="true"
/>
<i class="bi bi-dot" />
updated
{{ t('views.playlists.Detail.meta.updated') }}
<HumanDate
:date="playlist.modification_date"
/>