Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
946e3dd
Make project localizable.
RodoMa92 Jun 16, 2026
ce1a31f
Further translation work.
RodoMa92 Jun 16, 2026
c2ff6c1
Complete components and start context menu translations
RodoMa92 Jun 16, 2026
90acce8
Further translation work in all requests notification and
RodoMa92 Jun 17, 2026
c4d77a0
Fully translated settings pages
RodoMa92 Jun 17, 2026
da50185
Final translation merge, bugfixes and generic code cleanup
RodoMa92 Jun 17, 2026
ad7bb76
Final language cleanup and add a mockup user language
RodoMa92 Jun 17, 2026
ac0bbfc
Implement a client side language selector plus a cookie
RodoMa92 Jun 17, 2026
0d9672f
Update i18n deps as of 06/2026
RodoMa92 Jun 17, 2026
870dd97
Final cleanup pass of the original commits
RodoMa92 Jun 17, 2026
47bc4c6
Complete translation of the donate page and final cleanup of the tran…
RodoMa92 Jun 18, 2026
052eff7
Merge branch 'master' into feat_add_i18n
fg006 Sep 11, 2026
85dc997
remove stray <
fg006 Sep 11, 2026
a87e18e
pass fallbackLocale to createI18n
fg006 Sep 11, 2026
b3cf662
normalize locale string
fg006 Sep 11, 2026
827b9a5
format date with active locale
fg006 Sep 11, 2026
bf319a8
fix typo
fg006 Sep 11, 2026
42bcd54
fix master flag rendering
fg006 Sep 11, 2026
c5edd5a
bind language picker to useI18n refs
fg006 Sep 11, 2026
b9b2b82
fix quote error
fg006 Sep 11, 2026
2630783
index settings views by id
fg006 Sep 12, 2026
a603eb5
move full scan text to i18n
fg006 Sep 12, 2026
6ee4910
move language settings to appearance tab
fg006 Sep 12, 2026
0960028
port remainder strings to i18n
fg006 Sep 13, 2026
def0a47
add simplified chinese to i18n
fg006 Sep 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,7 @@ pnpm-debug.log*
# TODO.md

__pycache__
dev-dist/*
dev-dist/*

# Local patches
*.patch
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"vue": "^v3.5.13",
"vue-boring-avatars": "^1.4.0",
"vue-debounce": "^3.0.2",
"vue-i18n": "^11.4",
"vue-router": "^4.1.3",
"vue-template-compiler": "^2.0.0",
"vue-virtual-scroller": "^2.0.0-beta.7",
Expand Down
2 changes: 1 addition & 1 deletion src/assets/icons/expand.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions src/components/AlbumView/AlbumDiscBar.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<template>
<div v-if="album_disc.is_album_disc_number" class="album_disc_header no-select">
<div class="disc_number">
Disc {{ album_disc.album_page_disc_number }}
{{ $t('AlbumView.DiskNumber', { num: album_disc.album_page_disc_number }) }}
<span @click="$emit('playDisc', album_disc.album_page_disc_number || 0)" class="play">
<PlaySvg /> Play Disc {{ album_disc.album_page_disc_number }}</span
<PlaySvg /> {{ $t('AlbumView.PlayDisc') }} {{ album_disc.album_page_disc_number }}</span
>
</div>
<div class="play"></div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/AlbumView/GenreBanner.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
>
<div class="scrollable">
<div class="rounded pad-sm genre-pill">
{{ genres.length ? "Genres" : "No genres" }}
{{ genres.length ? $t('AlbumView.GenreBanner.GenreExists') : $t('AlbumView.GenreBanner.GenreDoesNotExist') }}
</div>
<div
v-for="genre in genres"
Expand Down
11 changes: 7 additions & 4 deletions src/components/AlbumView/Header/Stats.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,28 @@
:albumartists="''"
:small="true"
:append="!isSmallPhone ? statsText : ''"
:prepend="isSmallPhone ? 'Album by ' : ''"
:prepend="isSmallPhone ? $t('AlbumView.AlbumBy') : ''"
/>
</div>
<div v-if="isSmallPhone" class="stats2">
{{ new Date(album.date * 1000).getUTCFullYear() }} {{ !album.is_single ? `• ${album.trackcount} Tracks` : "" }} •
{{ new Date(album.date * 1000).getFullYear() }} {{ !album.is_single ? `• ${album.trackcount} ${ $t('Common.Track', album.trackcount) }` : "" }} •
{{ formatSeconds(album.duration, true) }}
</div>
</div>
</template>

<script setup lang="ts">
import { computed } from "vue";
import { useT } from "@/i18n";

import { Album } from "@/interfaces";
import { isSmallPhone } from "@/stores/content-width";
import { formatSeconds } from "@/utils";

import ArtistName from "@/components/shared/ArtistName.vue";

const { t } = useT();

const props = defineProps<{
album: Album;
}>();
Expand All @@ -33,8 +36,8 @@ const statsText = computed(() => {
const is_single = props.album.is_single;

// hide track count if it's a single, also add an s to track if it's plural
return `• ${new Date(props.album.date * 1000).getUTCFullYear()} ${
!is_single ? `• ${props.album.trackcount.toLocaleString()} Track${props.album.trackcount > 1 ? "s" : ""}` : ""
return `• ${new Date(props.album.date * 1000).getFullYear()} ${
!is_single ? `• ${props.album.trackcount.toLocaleString()} ${ t('Common.Track', props.album.trackcount) }` : ""
} • ${formatSeconds(props.album.duration, true)}`;
});
</script>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ArtistView/AlbumsFetcher.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div style="height: 1px">
<button v-if="show_text" @click="fetch_callback">Load More</button>
<button v-if="show_text" @click="fetch_callback">{{ $t('ArtistView.LoadMore') }}</button>
</div>
</template>

Expand Down
6 changes: 3 additions & 3 deletions src/components/ArtistView/HeaderComponents/Info.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
}"
>
<section class="text">
<div class="card-title">Artist</div>
<div class="card-title">{{ $t('ArtistView.Title') }}</div>
<div class="artist-name" :class="`${useCircularImage ? 'ellip' : 'ellip2'}`" :title="artist.name">
{{ artist.name }}
</div>
<div class="stats">
<span v-if="artist.trackcount">
{{ artist.trackcount.toLocaleString() }} Track{{ `${artist.trackcount == 1 ? '' : 's'} • ` }}
{{ artist.trackcount.toLocaleString() }} {{ `${ $t('Common.Track', artist.trackcount) } • `}}
</span>
<span v-if="artist.albumcount">
{{ artist.albumcount.toLocaleString() }} Album{{ `${artist.albumcount == 1 ? '' : 's'} • ` }}
{{ artist.albumcount.toLocaleString() }} {{ `${ $t('Common.Album', artist.albumcount) } • ` }}
</span>
<span v-if="artist.duration">
{{ `${formatSeconds(artist.duration, true)}` }}
Expand Down
3 changes: 2 additions & 1 deletion src/components/ArtistView/TopTracks.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
@playThis="playHandler(index)"
/>
</div>
<div v-if="!tracks.length" class="error">No tracks</div>
<div v-if="!tracks.length" class="error">{{ $t('ArtistView.NoTracks') }}</div>
</div>
</template>

Expand All @@ -25,6 +25,7 @@ import { isMedium, isSmall } from '@/stores/content-width'
import SeeAll from '../shared/SeeAll.vue'
import SongItem from '../shared/SongItem.vue'


defineProps<{
tracks: Track[]
route: string
Expand Down
6 changes: 3 additions & 3 deletions src/components/BottomBar/Left.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
/>
<RouterLink
v-else
title="Go to Now Playing"
:title="$t('BottomBar.GoToNowPlaying')"
:to="{
name: Routes.nowPlaying,
params: {
Expand Down Expand Up @@ -37,7 +37,7 @@
>
<div v-tooltip class="title">
<TextLoader
:text="queue.currenttrack?.title || 'Hello there'"
:text="queue.currenttrack?.title || $t('BottomBar.PlaceholderTitle') "
:duration="1000"
:fade-duration="1000"
:direction="queue.direction"
Expand All @@ -51,7 +51,7 @@
</div>
<ArtistName
:artists="queue.currenttrack?.artists || []"
:albumartists="queue.currenttrack?.albumartists || 'Welcome to Swing Music'"
:albumartists="queue.currenttrack?.albumartists || $t('BottomBar.PlaceholderArtist')"
class="artist"
/>
</div>
Expand Down
7 changes: 4 additions & 3 deletions src/components/BottomBar/Right.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@
<button
class="repeat"
:class="{ 'repeat-disabled': settings.repeat == 'none' }"
:title="settings.repeat == 'all' ? 'Repeat all' : settings.repeat == 'one' ? 'Repeat one' : 'No repeat'"
:title="settings.repeat == 'all' ? $t('BottomBar.RepeatOptions.All') : settings.repeat == 'one' ? $t('BottomBar.RepeatOptions.One') : $t('BottomBar.RepeatOptions.None')"
@click="settings.toggleRepeatMode"
>
<RepeatOneSvg v-if="settings.repeat == 'one'" />
<RepeatAllSvg v-else />
</button>
<button class="shuffle" title="Shuffle" @click="queue.shuffleQueue">
<button class="shuffle" :title="$t('BottomBar.Shuffle')" @click="queue.shuffleQueue">
<ShuffleSvg />
</button>
<HeartSvg
v-if="!hideHeart"
title="Favorite"
:title="$t('BottomBar.Favorite')"
:state="queue.currenttrack?.is_favorite"
@handleFav="() => $emit('handleFav')"
/>
Expand All @@ -27,6 +27,7 @@
import useQueue from '@/stores/queue'
import useSettings from '@/stores/settings'


import RepeatOneSvg from '@/assets/icons/repeat-one.svg'
import RepeatAllSvg from '@/assets/icons/repeat.svg'
import ShuffleSvg from '@/assets/icons/shuffle.svg'
Expand Down
2 changes: 1 addition & 1 deletion src/components/BottomBar/Volume.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
min="0"
step="0.01"
:value="settings.volume"
:aria-label="`Volume ${volume_percent} percent`"
:aria-label="$t('BottomBar.VolumeLabel', { percent: volume_percent })"
:aria-valuetext="`${volume_percent}%`"
:style="{
backgroundSize: `${volume_percent}% 100%`,
Expand Down
27 changes: 15 additions & 12 deletions src/components/CardListView/SortBanner.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div class="itemsortby">
<div class="tt select circular">Sort By</div>
<div class="tt select circular">{{ $t('CardList.SortBy') }}</div>
<div class="left group">
<SortKey
:items="($route.name == Routes.AlbumList ? albumitems : artistitems).concat(items)"
Expand All @@ -22,31 +22,34 @@ import { useRoute } from 'vue-router'
import { useAlbumList, useArtistList } from '@/stores/pages/itemlist'
import SortKey from './SortKey.vue'
import ChartSvg from '@/assets/icons/chart.svg'
import { useT } from '@/i18n'

const { t } = useT();

const route = useRoute()
const store = route.name === Routes.AlbumList ? useAlbumList() : useArtistList()

const items = [
{ key: 'trackcount', displayName: 'No. of tracks' },
{ key: 'duration', displayName: 'Duration' },
{ key: 'created_date', displayName: 'Date added' },
{ key: 'lastplayed', displayName: 'Last played' },
{ key: 'trackcount', displayName: t('CardList.SortByOptions.TrackCount') },
{ key: 'duration', displayName: t('CardList.SortByOptions.Duration') },
{ key: 'created_date', displayName: t('CardList.SortByOptions.CreatedDate') },
{ key: 'lastplayed', displayName: t('CardList.SortByOptions.LastPlayed') },
]

const statitems = [
{ key: 'playcount', displayName: 'Plays' },
{ key: 'playduration', displayName: 'Play duration' },
{ key: 'playcount', displayName: t('CardList.SortByOptions.PlayCount') },
{ key: 'playduration', displayName: t('CardList.SortByOptions.PlayDuration') },
]

const albumitems = [
{ key: 'title', displayName: 'Title' },
{ key: 'albumartists', displayName: 'Artist' },
{ key: 'date', displayName: 'Year released' },
{ key: 'title', displayName: t('CardList.SortByOptions.Title') },
{ key: 'albumartists', displayName: t('CardList.SortByOptions.AlbumArtists') },
{ key: 'date', displayName: t('CardList.SortByOptions.Date') },
]

const artistitems = [
{ key: 'name', displayName: 'Name' },
{ key: 'albumcount', displayName: 'No. of albums' },
{ key: 'name', displayName: t('CardList.SortByOptions.Name') },
{ key: 'albumcount', displayName: t('CardList.SortByOptions.NoOfAlbums') },
]
</script>

Expand Down
2 changes: 1 addition & 1 deletion src/components/Classical/WorkHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div class="workheader">
<div class="workcomposer">
<span v-if="work.composer" class="composername">{{ work.composer }}</span>
<span v-if="playable" class="play" @click.stop="$emit('playWork')"> <PlaySvg /> Play</span>
<span v-if="playable" class="play" @click.stop="$emit('playWork')"> <PlaySvg /> {{ $t('Common.Play') }}</span>
</div>
<div class="worktitle">
{{ title }}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Favorites/RecentsItemCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
{{ fav.type === "artist" ? fav.item.name : fav.item.title }}
</div>
<div class="label ellip" :class="{ on_artist: fav.type === 'artist' }">
{{ fav.type === "album" ? fav.item.artist : "Artist" }}
{{ fav.type === "album" ? fav.item.artist : $t('Favorites.Album')}}
</div>
</RouterLink>
</template>
Expand Down
4 changes: 2 additions & 2 deletions src/components/FolderView/FolderItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
<FolderSvg v-else />
<div class="info">
<div class="f-item-text ellip">{{ folder.name }}</div>
<div class="f-count" v-if="folder.trackcount">
{{ folder.trackcount.toLocaleString() + ` File${folder.trackcount == 1 ? "" : "s"}` }}
<div v-if="folder.trackcount" class="f-count">
{{ folder.trackcount.toLocaleString() + ' ' + $t('FolderView.FileCount', folder.trackcount) }}
</div>
</div>
<div v-if="!folder_page" class="check">
Expand Down
26 changes: 15 additions & 11 deletions src/components/HomeView/Browse.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div class="homebrowse">
<div class="btitle"><b>Browse Library</b></div>
<div class="btitle"><b>{{ $t('HomeView.Browse.Title') }}</b></div>
<div class="browselist">
<RouterLink
v-for="i in browselist"
Expand Down Expand Up @@ -30,57 +30,61 @@ import {
} from "@/icons";
import { Routes } from "@/router";
import { album_card_with } from "@/stores/content-width";
import useDialog from "@/stores/modal";
import { useT } from "@/i18n";

const { t } = useT();

const browselist = [
{
title: "Folders",
title: t('HomeView.Browse.BrowseList.Folders'),
route: Routes.folder,
params: {
path: "$home",
},
icon: FolderIcon,
},
{
title: "Albums",
title: t('HomeView.Browse.BrowseList.Albums'),
route: Routes.AlbumList,
icon: AlbumIcon,
},
{
title: "Artists",
title: t('HomeView.Browse.BrowseList.Artists'),
route: Routes.ArtistList,
icon: ArtistIcon,
},
{
title: "Playlists",
title: t('HomeView.Browse.BrowseList.Playlists'),
route: Routes.playlists,
icon: PlaylistIcon,
},
{
title: "Favorites",
title: t('HomeView.Browse.BrowseList.Favorites'),
route: Routes.favorites,
icon: HeartIcon,
class: "favorite",
},
{
title: "Fav. tracks",
title: t('HomeView.Browse.BrowseList.FavTracks'),
route: Routes.favoriteTracks,
icon: HeartIcon,
class: "favorite",
},
{
title: "Fav. artists",
title: t('HomeView.Browse.BrowseList.FavArtists'),
route: Routes.favoriteArtists,
icon: ArtistIcon,
class: "favorite",
},
{
title: "Fav. albums",
title: t('HomeView.Browse.BrowseList.FavAlbums'),
route: Routes.favoriteAlbums,
icon: AlbumIcon,
class: "favorite",
},
// {
// title: "Settings",
// title: t('Common.Settings'),
// route: null,
// icon: SettingsIcon,
// action: () => {
Expand All @@ -89,7 +93,7 @@ const browselist = [
// class: "settings",
// },
{
title: "Stats",
title: t('HomeView.Browse.BrowseList.Stats'),
icon: AlbumIcon,
route: Routes.Stats,
}
Expand Down
3 changes: 2 additions & 1 deletion src/components/LeftSidebar/MobileNav.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@
</template>

<script setup lang="ts">
import { menus } from "./navitems";
import { useNavItems } from "../LeftSidebar/navitems";
const { menus } = useNavItems();
</script>
2 changes: 1 addition & 1 deletion src/components/LeftSidebar/NP/Bitrate.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div v-if="q.currenttrack?.bitrate" class="bitrate" title="file type • bitrate">
<div v-if="q.currenttrack?.bitrate" class="bitrate" :title="$t('LeftSidebar.FileTypeBitrate')">
{{ q.currenttrack.filepath?.split(".").pop() }} • {{ q.currenttrack.bitrate }}
</div>
</template>
Expand Down
3 changes: 2 additions & 1 deletion src/components/LeftSidebar/NavButtons.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
</template>

<script setup lang="ts">
import { menus } from "./navitems";
import { useNavItems } from "../LeftSidebar/navitems";
const { menus } = useNavItems();
</script>

<style lang="scss">
Expand Down
Loading