added language change logic, added flags, added more translations

This commit is contained in:
Roberto Tonino 2020-07-18 22:44:27 +02:00
parent dc95150d7f
commit 636701aa70
14 changed files with 1553 additions and 70 deletions

1356
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -19,6 +19,7 @@
"dependencies": { "dependencies": {
"jquery": "^3.5.1", "jquery": "^3.5.1",
"lodash-es": "^4.17.15", "lodash-es": "^4.17.15",
"svg-country-flags": "^1.2.7",
"toastify-js": "^1.8.0", "toastify-js": "^1.8.0",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-i18n": "^8.18.2" "vue-i18n": "^8.18.2"
@ -28,10 +29,12 @@
"@rollup/plugin-commonjs": "^11.0.2", "@rollup/plugin-commonjs": "^11.0.2",
"@rollup/plugin-node-resolve": "^8.0.1", "@rollup/plugin-node-resolve": "^8.0.1",
"@rollup/plugin-replace": "^2.3.2", "@rollup/plugin-replace": "^2.3.2",
"node-sass": "^4.14.1",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rollup": "^2.14.0", "rollup": "^2.14.0",
"rollup-plugin-analyzer": "^3.2.3", "rollup-plugin-analyzer": "^3.2.3",
"rollup-plugin-svg": "^2.0.0",
"rollup-plugin-terser": "^6.1.0", "rollup-plugin-terser": "^6.1.0",
"rollup-plugin-vue": "^4.2.0", "rollup-plugin-vue": "^4.2.0",
"sass": "^1.26.8", "sass": "^1.26.8",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,7 @@ import replace from '@rollup/plugin-replace'
import alias from '@rollup/plugin-alias' import alias from '@rollup/plugin-alias'
import analyze from 'rollup-plugin-analyzer' import analyze from 'rollup-plugin-analyzer'
import vue from 'rollup-plugin-vue' import vue from 'rollup-plugin-vue'
import svg from 'rollup-plugin-svg'
// 'rollup -c' -> 'production' is false // 'rollup -c' -> 'production' is false
// 'rollup -c -w' -> 'production' is true // 'rollup -c -w' -> 'production' is true
@ -46,6 +47,7 @@ export default {
}), }),
resolve(), // Tells Rollup how to find imported modules in node_modules resolve(), // Tells Rollup how to find imported modules in node_modules
commonjs(), // Converts imported modules to ES modules, if necessary commonjs(), // Converts imported modules to ES modules, if necessary
svg(),
vue(), vue(),
production && terser(), // Minify, but only in production production && terser(), // Minify, but only in production
production && analyze({ showExports: true, limit: 15 }) // Show useful information about bundles, only in production production && analyze({ showExports: true, limit: 15 }) // Show useful information about bundles, only in production

38
src/assets/it.svg Normal file
View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<circle style="fill:#F0F0F0;" cx="256" cy="256" r="256"/>
<path style="fill:#D80027;" d="M512,256c0-110.071-69.472-203.906-166.957-240.077v480.155C442.528,459.906,512,366.071,512,256z"/>
<path style="fill:#6DA544;" d="M0,256c0,110.071,69.472,203.906,166.957,240.077V15.923C69.472,52.094,0,145.929,0,256z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 803 B

View File

@ -9,7 +9,7 @@
type="search" type="search"
name="searchbar" name="searchbar"
value="" value=""
placeholder="Search what you want (or just paste a link)" :placeholder="$t('searchbar')"
autofocus autofocus
ref="searchbar" ref="searchbar"
@keyup="handleSearchBarKeyup($event)" @keyup="handleSearchBarKeyup($event)"

View File

@ -33,15 +33,17 @@
<h3 class="settings-group__header settings-group__header--with-icon"> <h3 class="settings-group__header settings-group__header--with-icon">
<i class="material-icons">language</i>{{ $t('settings.languages') }} <i class="material-icons">language</i>{{ $t('settings.languages') }}
</h3> </h3>
<span <div>
v-for="locale in locales" <span
:key="locale" v-for="locale in locales"
style="width: 50px; height: 50px; cursor:pointer; border: 1px solid var(--foreground); flex: 1 50px; display: flex; justify-content: center; align-items: center;" :key="locale"
:data-locale="locale" class="locale-flag"
@click="$i18n.locale = locale" :class="{ 'locale-flag--current': currentLocale === locale }"
> @click="changeLocale(locale)"
{{ locale.toUpperCase() }} v-html="flags[locale]"
</span> >
</span>
</div>
</div> </div>
<div class="settings-group"> <div class="settings-group">
@ -557,15 +559,43 @@
</footer> </footer>
</div> </div>
</template> </template>
<style lang="scss">
.locale-flag {
width: 60px;
display: inline-flex;
justify-content: center;
align-items: center;
cursor: pointer;
&:not(:last-child) {
margin-right: 10px;
}
&.locale-flag--current {
svg {
filter: brightness(1);
}
}
svg {
width: 40px;
height: 40px;
filter: brightness(0.5);
}
}
</style>
<script> <script>
import { toast } from '@/utils/toasts' import { toast } from '@/utils/toasts'
import { socket } from '@/utils/socket' import { socket } from '@/utils/socket'
import EventBus from '@/utils/EventBus' import EventBus from '@/utils/EventBus'
import flags from '@/utils/flags'
export default { export default {
name: 'the-settings-tab', name: 'the-settings-tab',
data: () => ({ data: () => ({
flags,
currentLocale: 'en',
locales: [], locales: [],
settings: { tags: {} }, settings: { tags: {} },
lastSettings: {}, lastSettings: {},
@ -610,6 +640,11 @@ export default {
toast(this.$t('settings.toasts.ARLcopied'), 'assignment') toast(this.$t('settings.toasts.ARLcopied'), 'assignment')
}, },
changeLocale(newLocale) {
this.$i18n.locale = newLocale
this.currentLocale = newLocale
localStorage.setItem('locale', newLocale)
},
updateMaxVolume() { updateMaxVolume() {
localStorage.setItem('previewVolume', this.previewVolume.preview_max_volume) localStorage.setItem('previewVolume', this.previewVolume.preview_max_volume)
}, },
@ -677,11 +712,23 @@ export default {
this.$refs.loggedInInfo.classList.add('hide') this.$refs.loggedInInfo.classList.add('hide')
if (localStorage.getItem('arl')) { let storedLocale = localStorage.getItem('locale')
this.$refs.loginInput.value = localStorage.getItem('arl').trim()
if (storedLocale) {
this.$i18n.locale = storedLocale
this.currentLocale = storedLocale
} }
if (localStorage.getItem('accountNum')) {
this.accountNum = localStorage.getItem('accountNum') let storedArl = localStorage.getItem('arl')
if (storedArl) {
this.$refs.loginInput.value = storedArl.trim()
}
let storedAccountNum = localStorage.getItem('accountNum')
if (storedAccountNum) {
this.accountNum = storedAccountNum
} }
let spotifyUser = localStorage.getItem('spotifyUser') let spotifyUser = localStorage.getItem('spotifyUser')
@ -709,5 +756,4 @@ export default {
} }
</script> </script>
<style>
</style>

View File

@ -2,50 +2,42 @@
<aside id="sidebar" role="navigation" @click="handleSidebarClick"> <aside id="sidebar" role="navigation" @click="handleSidebarClick">
<span id="main_home_tablink" class="main_tablinks" role="link" aria-label="home"> <span id="main_home_tablink" class="main_tablinks" role="link" aria-label="home">
<i class="material-icons side_icon">home</i> <i class="material-icons side_icon">home</i>
<span class="main_tablinks_text">Home</span> <span class="main_tablinks_text">{{ $t('sidebar.home') }}</span>
</span> </span>
<span id="main_search_tablink" class="main_tablinks" role="link" aria-label="search"> <span id="main_search_tablink" class="main_tablinks" role="link" aria-label="search">
<i class="material-icons side_icon">search</i> <i class="material-icons side_icon">search</i>
<span class="main_tablinks_text">Search</span> <span class="main_tablinks_text">{{ $t('sidebar.search') }}</span>
</span> </span>
<span id="main_charts_tablink" class="main_tablinks" role="link" aria-label="charts"> <span id="main_charts_tablink" class="main_tablinks" role="link" aria-label="charts">
<i class="material-icons side_icon">bubble_chart</i> <i class="material-icons side_icon">bubble_chart</i>
<span class="main_tablinks_text">Charts</span> <span class="main_tablinks_text">{{ $t('sidebar.charts') }}</span>
</span> </span>
<span id="main_favorites_tablink" class="main_tablinks" role="link" aria-label="favorites"> <span id="main_favorites_tablink" class="main_tablinks" role="link" aria-label="favorites">
<i class="material-icons side_icon">album</i> <i class="material-icons side_icon">album</i>
<span class="main_tablinks_text">Favorites</span> <span class="main_tablinks_text">{{ $t('sidebar.favorites') }}</span>
</span> </span>
<span id="main_analyzer_tablink" class="main_tablinks" role="link" aria-label="link analyzer"> <span id="main_analyzer_tablink" class="main_tablinks" role="link" aria-label="link analyzer">
<i class="material-icons side_icon">link</i> <i class="material-icons side_icon">link</i>
<span class="main_tablinks_text">Link Analyzer</span> <span class="main_tablinks_text">{{ $t('sidebar.linkAnalyzer') }}</span>
</span> </span>
<span id="main_settings_tablink" class="main_tablinks" role="link" aria-label="settings"> <span id="main_settings_tablink" class="main_tablinks" role="link" aria-label="settings">
<i class="material-icons side_icon">settings</i> <i class="material-icons side_icon">settings</i>
<span class="main_tablinks_text">Settings</span> <span class="main_tablinks_text">{{ $t('sidebar.settings') }}</span>
</span> </span>
<span id="main_about_tablink" class="main_tablinks" role="link" aria-label="info"> <span id="main_about_tablink" class="main_tablinks" role="link" aria-label="info">
<i class="material-icons side_icon">info</i> <i class="material-icons side_icon">info</i>
<span class="main_tablinks_text">About</span> <span class="main_tablinks_text">{{ $t('sidebar.about') }}</span>
</span> </span>
<span id="theme_selector" class="main_tablinks" role="link" aria-label="theme selector"> <span id="theme_selector" class="main_tablinks" role="link" aria-label="theme selector">
<i class="material-icons side_icon side_icon--theme">palette</i> <i class="material-icons side_icon side_icon--theme">palette</i>
<div id="theme_togglers"> <div id="theme_togglers">
<div <div
class="theme_toggler theme_toggler--purple" v-for="theme of themes"
:class="{ 'theme_toggler--active': activeTheme === 'purple' }" :key="theme"
@click="changeTheme('purple')" class="theme_toggler "
/> :class="[{ 'theme_toggler--active': activeTheme === theme }, `theme_toggler--${theme}`]"
<div @click="changeTheme(theme)"
class="theme_toggler theme_toggler--dark" ></div>
:class="{ 'theme_toggler--active': activeTheme === 'dark' }"
@click="changeTheme('dark')"
/>
<div
class="theme_toggler theme_toggler--light"
:class="{ 'theme_toggler--active': activeTheme === 'light' }"
@click="changeTheme('light')"
/>
</div> </div>
</span> </span>
<div id="network-status" :class="{ online: appOnline, offline: !appOnline }"> <div id="network-status" :class="{ online: appOnline, offline: !appOnline }">
@ -89,12 +81,11 @@ import { changeTab } from '@js/tabs.js'
export default { export default {
name: 'the-sidebar', name: 'the-sidebar',
data() { data: () => ({
return { appOnline: null,
appOnline: null, activeTheme: 'light',
activeTheme: 'light' themes: ['purple', 'dark', 'light']
} }),
},
mounted() { mounted() {
/* === Online status handling === */ /* === Online status handling === */
this.appOnline = navigator.onLine this.appOnline = navigator.onLine

View File

@ -10,8 +10,8 @@
{{ title }} <i v-if="explicit" class="material-icons explicit_icon explicit_icon--right">explicit</i> {{ title }} <i v-if="explicit" class="material-icons explicit_icon explicit_icon--right">explicit</i>
</h1> </h1>
<h2 class="inline-flex"> <h2 class="inline-flex">
<span v-if="metadata">{{ metadata }}</span <span v-if="metadata">{{ metadata }}</span>
><span class="right" v-if="release_date">{{ release_date }}</span> <span class="right" v-if="release_date">{{ release_date }}</span>
</h2> </h2>
</header> </header>
@ -22,9 +22,9 @@
<i class="material-icons">music_note</i> <i class="material-icons">music_note</i>
</th> </th>
<th>#</th> <th>#</th>
<th>Song</th> <th>{{ $tc('globals.listTabs.track', 1) }}</th>
<th>Artist</th> <th>{{ $tc('globals.listTabs.artist', 1) }}</th>
<th v-if="type == 'Playlist'">Album</th> <th v-if="type === 'Playlist'">{{ $tc('globals.listTabs.album', 1) }}</th>
<th> <th>
<i class="material-icons">timer</i> <i class="material-icons">timer</i>
</th> </th>
@ -111,8 +111,9 @@
@click="playPausePreview" @click="playPausePreview"
:class="'material-icons' + (track.preview_url ? ' preview_playlist_controls' : '')" :class="'material-icons' + (track.preview_url ? ' preview_playlist_controls' : '')"
:data-preview="track.preview_url" :data-preview="track.preview_url"
>play_arrow</i
> >
play_arrow
</i>
<i v-else class="material-icons disabled">play_arrow</i> <i v-else class="material-icons disabled">play_arrow</i>
</td> </td>
<td>{{ i + 1 }}</td> <td>{{ i + 1 }}</td>
@ -131,7 +132,8 @@
<span v-if="label" style="opacity: 0.40;margin-top: 8px;display: inline-block;font-size: 13px;">{{ label }}</span> <span v-if="label" style="opacity: 0.40;margin-top: 8px;display: inline-block;font-size: 13px;">{{ label }}</span>
<footer> <footer>
<button @contextmenu.prevent="openQualityModal" @click.stop="addToQueue" :data-link="link"> <button @contextmenu.prevent="openQualityModal" @click.stop="addToQueue" :data-link="link">
Download {{ type }} <!-- vue-i18n throws a warning beacuse of the reset -->
{{ `${$t('globals.download')} ${$tc(`globals.listTabs.${type}`, 1)}` }}
</button> </button>
<button <button
class="with_icon" class="with_icon"
@ -139,9 +141,9 @@
@click.stop="addToQueue" @click.stop="addToQueue"
:data-link="selectedLinks()" :data-link="selectedLinks()"
> >
Download selection<i class="material-icons">file_download</i> {{ $t('tracklist.downloadSelection') }}<i class="material-icons">file_download</i>
</button> </button>
<button class="back-button">Back</button> <button class="back-button">{{ $t('globals.back') }}</button>
</footer> </footer>
</div> </div>
</template> </template>
@ -163,7 +165,7 @@ export default {
label: '', label: '',
explicit: false, explicit: false,
image: '', image: '',
type: '', type: 'empty',
link: '', link: '',
body: [] body: []
}), }),
@ -180,7 +182,7 @@ export default {
this.label = '' this.label = ''
this.release_date = '' this.release_date = ''
this.explicit = false this.explicit = false
this.type = '' this.type = 'empty'
this.body = [] this.body = []
}, },
addToQueue(e) { addToQueue(e) {
@ -220,12 +222,12 @@ export default {
cover_xl cover_xl
} = data } = data
this.type = 'Album' this.type = `${this.$tc('globals.listTabs.album', 1)}`
this.link = `https://www.deezer.com/album/${albumID}` this.link = `https://www.deezer.com/album/${albumID}`
this.title = albumTitle this.title = albumTitle
this.explicit = explicit_lyrics this.explicit = explicit_lyrics
this.label = albumLabel this.label = albumLabel
this.metadata = `${artistName}${numberOfTracks} songs` this.metadata = `${artistName}${numberOfTracks} ${this.$tc('globals.listTabs.track', 2)}`
this.release_date = release_date.substring(0, 10) this.release_date = release_date.substring(0, 10)
this.image = cover_xl this.image = cover_xl
@ -246,12 +248,15 @@ export default {
tracks: { length: numberOfTracks } tracks: { length: numberOfTracks }
} = data } = data
this.type = 'Playlist' this.type = `${this.$tc('globals.listTabs.playlist', 1)}`
this.link = `https://www.deezer.com/playlist/${playlistID}` this.link = `https://www.deezer.com/playlist/${playlistID}`
this.title = playlistTitle this.title = playlistTitle
this.image = playlistCover this.image = playlistCover
this.release_date = creation_date.substring(0, 10) this.release_date = creation_date.substring(0, 10)
this.metadata = `by ${creatorName}${numberOfTracks} songs` this.metadata = `${this.$t('globals.by')} ${creatorName}${numberOfTracks} ${this.$tc(
'globals.listTabs.track',
2
)}`
if (isEmpty(playlistTracks)) { if (isEmpty(playlistTracks)) {
this.body = null this.body = null
@ -270,14 +275,17 @@ export default {
tracks: { length: numberOfTracks } tracks: { length: numberOfTracks }
} = data } = data
this.type = 'Spotify Playlist' this.type = `${this.$tc('globals.listTabs.spotifyPlaylist', 1)}`
this.link = playlistURI this.link = playlistURI
this.title = playlistName this.title = playlistName
this.image = numberOfImages this.image = numberOfImages
? images[0].url ? images[0].url
: 'https://e-cdns-images.dzcdn.net/images/cover/d41d8cd98f00b204e9800998ecf8427e/1000x1000-000000-80-0-0.jpg' : 'https://e-cdns-images.dzcdn.net/images/cover/d41d8cd98f00b204e9800998ecf8427e/1000x1000-000000-80-0-0.jpg'
this.release_date = '' this.release_date = ''
this.metadata = `by ${ownerName}${numberOfTracks} songs` this.metadata = `${this.$t('globals.by')} ${ownerName}${numberOfTracks} ${this.$tc(
'globals.listTabs.track',
2
)}`
if (isEmpty(playlistTracks)) { if (isEmpty(playlistTracks)) {
this.body = null this.body = null

View File

@ -6,6 +6,7 @@ const en = {
download: 'Download', download: 'Download',
by: 'by', by: 'by',
listTabs: { listTabs: {
empty: '',
all: 'all', all: 'all',
album: 'album | albums', album: 'album | albums',
artist: 'artist | artists', artist: 'artist | artists',
@ -13,6 +14,7 @@ const en = {
title: 'title | titles', title: 'title | titles',
track: 'track | tracks', track: 'track | tracks',
playlist: 'playlist | playlists', playlist: 'playlist | playlists',
spotifyPlaylist: 'spotify playlist | spotify playlists',
releaseDate: 'release date', releaseDate: 'release date',
error: 'error' error: 'error'
} }
@ -40,6 +42,7 @@ const en = {
popularAlbums: 'Most streamed albums' popularAlbums: 'Most streamed albums'
} }
}, },
searchbar: 'Search anything you want (or just paste a link)',
settings: { settings: {
title: 'Settings', title: 'Settings',
languages: 'Languages', languages: 'Languages',
@ -117,9 +120,9 @@ const en = {
embeddedArtworkSize: 'Embedded artwork size', embeddedArtworkSize: 'Embedded artwork size',
localArtworkFormat: { localArtworkFormat: {
title: 'What format do you want the local artwork to be?', title: 'What format do you want the local artwork to be?',
jpg: "A jpeg image", jpg: 'A jpeg image',
png: "A png image", png: 'A png image',
both: "Both a jpeg and a png" both: 'Both a jpeg and a png'
}, },
jpegImageQuality: 'JPEG image quality' jpegImageQuality: 'JPEG image quality'
}, },
@ -206,6 +209,18 @@ const en = {
update: 'Settings updated!', update: 'Settings updated!',
ARLcopied: 'ARL copied to clipboard' ARLcopied: 'ARL copied to clipboard'
} }
},
sidebar: {
home: 'home',
search: 'search',
charts: 'charts',
favorites: 'favorites',
linkAnalyzer: 'link analyzer',
settings: 'settings',
about: 'about'
},
tracklist: {
downloadSelection: 'Download selection'
} }
} }

View File

@ -13,8 +13,10 @@ const it = {
title: 'titolo | titoli', title: 'titolo | titoli',
track: 'traccia | tracce', track: 'traccia | tracce',
playlist: 'playlist', playlist: 'playlist',
spotifyPlaylist: 'playlist spotify',
releaseDate: 'data di rilascio', releaseDate: 'data di rilascio',
error: 'errore' error: 'errore',
empty: ''
} }
}, },
charts: { charts: {
@ -40,6 +42,7 @@ const it = {
popularAlbums: 'Album più riprodotti' popularAlbums: 'Album più riprodotti'
} }
}, },
searchbar: 'Cerca qualsiasi cosa (o incolla semplicemente un link)',
settings: { settings: {
title: 'Impostazioni', title: 'Impostazioni',
languages: 'Lingue', languages: 'Lingue',
@ -156,12 +159,12 @@ const it = {
saveID3v1: 'Salva anche il ID3v1', saveID3v1: 'Salva anche il ID3v1',
multiArtistSeparator: { multiArtistSeparator: {
title: 'Come vuoi separare gli artisti?', title: 'Come vuoi separare gli artisti?',
nothing: 'Salva solo l\'artista principale', nothing: "Salva solo l'artista principale",
default: 'Usando la specificazione standard', default: 'Usando la specificazione standard',
andFeat: 'Usando & e feat.', andFeat: 'Usando & e feat.',
using: 'Usando "{0}"' using: 'Usando "{0}"'
}, },
singleAlbumArtist: 'Salva solo l\'artista dell\'album principale', singleAlbumArtist: "Salva solo l'artista dell'album principale",
albumVariousArtists: 'Lascia "Artisti Vari" negli artisti dell\'album', albumVariousArtists: 'Lascia "Artisti Vari" negli artisti dell\'album',
removeAlbumVersion: 'Rimuovi "Album Version" dal titolo del brano', removeAlbumVersion: 'Rimuovi "Album Version" dal titolo del brano',
removeDuplicateArtists: 'Rimuovi le combinazioni di artisti', removeDuplicateArtists: 'Rimuovi le combinazioni di artisti',
@ -206,6 +209,18 @@ const it = {
update: 'Impostazioni aggiornate!', update: 'Impostazioni aggiornate!',
ARLcopied: 'ARL copiato negli appunti' ARLcopied: 'ARL copiato negli appunti'
} }
},
sidebar: {
home: 'home',
search: 'ricerca',
charts: 'classifiche',
favorites: 'preferiti',
linkAnalyzer: 'analizza link',
settings: 'impostazioni',
about: 'info'
},
tracklist: {
downloadSelection: 'Scarica selezionati'
} }
} }

View File

@ -45,6 +45,8 @@ $sidebar-delay: 75ms;
margin-left: 20px; margin-left: 20px;
opacity: 0; opacity: 0;
overflow: hidden; overflow: hidden;
text-transform: capitalize;
letter-spacing: 1.3px;
white-space: nowrap; white-space: nowrap;
transition: all 50ms ease-in-out 200ms; transition: all 50ms ease-in-out 200ms;
} }

7
src/utils/flags.js Normal file
View File

@ -0,0 +1,7 @@
import it from 'svg-country-flags/svg/it.svg'
import gb from 'svg-country-flags/svg/gb.svg'
export default {
it,
en: gb
}