Skip to content
Snippets Groups Projects
Commit 98381a00 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Merge branch 'i18n' into 'develop'

I18n

Closes #5

See merge request funkwhale/funkwhale!125
parents e608de2c 1341c9aa
No related branches found
No related tags found
No related merge requests found
Showing
with 8277 additions and 106 deletions
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<modal class="small" :show.sync="showModal"> <modal class="small" :show.sync="showModal">
<div class="header"> <div class="header">
<slot name="modal-header">Do you want to confirm this action?</slot> <slot name="modal-header"><i18next path="Do you want to confirm this action?"/></slot>
</div> </div>
<div class="scrolling content"> <div class="scrolling content">
<div class="description"> <div class="description">
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
</div> </div>
</div> </div>
<div class="actions"> <div class="actions">
<div class="ui cancel button">Cancel</div> <div class="ui cancel button"><i18next path="Cancel"/></div>
<div :class="['ui', 'confirm', color, 'button']" @click="confirm"> <div :class="['ui', 'confirm', color, 'button']" @click="confirm">
<slot name="modal-confirm">Confirm</slot> <slot name="modal-confirm"><i18next path="Confirm"/></slot>
</div> </div>
</div> </div>
</modal> </modal>
......
...@@ -11,11 +11,13 @@ ...@@ -11,11 +11,13 @@
<span <span
@click="collapsed = false" @click="collapsed = false"
v-if="truncated && collapsed" v-if="truncated && collapsed"
class="expand">Expand</span> class="expand"
<span path="Expand"/>
<i18next
@click="collapsed = true" @click="collapsed = true"
v-if="truncated && !collapsed" v-if="truncated && !collapsed"
class="collapse">Collapse</span> class="collapse"
path="Collapse"/>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -2,11 +2,13 @@ ...@@ -2,11 +2,13 @@
<div class="main pusher" v-title="'Your Favorites'"> <div class="main pusher" v-title="'Your Favorites'">
<div class="ui vertical center aligned stripe segment"> <div class="ui vertical center aligned stripe segment">
<div :class="['ui', {'active': isLoading}, 'inverted', 'dimmer']"> <div :class="['ui', {'active': isLoading}, 'inverted', 'dimmer']">
<div class="ui text loader">Loading your favorites...</div> <div class="ui text loader"><i18next path="Loading your favorites..."/></div>
</div> </div>
<h2 v-if="results" class="ui center aligned icon header"> <h2 v-if="results" class="ui center aligned icon header">
<i class="circular inverted heart pink icon"></i> <i class="circular inverted heart pink icon"></i>
{{ $store.state.favorites.count }} favorites <i18next path="{%0%} favorites">
{{ $store.state.favorites.count }}
</i18next>
</h2> </h2>
<radio-button type="favorites"></radio-button> <radio-button type="favorites"></radio-button>
</div> </div>
...@@ -14,7 +16,7 @@ ...@@ -14,7 +16,7 @@
<div :class="['ui', {'loading': isLoading}, 'form']"> <div :class="['ui', {'loading': isLoading}, 'form']">
<div class="fields"> <div class="fields">
<div class="field"> <div class="field">
<label>Ordering</label> <i18next tag="label" path="Ordering"/>
<select class="ui dropdown" v-model="ordering"> <select class="ui dropdown" v-model="ordering">
<option v-for="option in orderingOptions" :value="option[0]"> <option v-for="option in orderingOptions" :value="option[0]">
{{ option[1] }} {{ option[1] }}
...@@ -22,14 +24,14 @@ ...@@ -22,14 +24,14 @@
</select> </select>
</div> </div>
<div class="field"> <div class="field">
<label>Ordering direction</label> <i18next tag="label" path="Ordering direction"/>
<select class="ui dropdown" v-model="orderingDirection"> <select class="ui dropdown" v-model="orderingDirection">
<option value="">Ascending</option> <option value=""><i18next path="Ascending"/></option>
<option value="-">Descending</option> <option value="-"><i18next path="Descending"/></option>
</select> </select>
</div> </div>
<div class="field"> <div class="field">
<label>Results per page</label> <i18next tag="label" path="Results per page"/>
<select class="ui dropdown" v-model="paginateBy"> <select class="ui dropdown" v-model="paginateBy">
<option :value="parseInt(12)">12</option> <option :value="parseInt(12)">12</option>
<option :value="parseInt(25)">25</option> <option :value="parseInt(25)">25</option>
...@@ -83,9 +85,9 @@ export default { ...@@ -83,9 +85,9 @@ export default {
orderingDirection: defaultOrdering.direction, orderingDirection: defaultOrdering.direction,
ordering: defaultOrdering.field, ordering: defaultOrdering.field,
orderingOptions: [ orderingOptions: [
['title', 'Track name'], ['title', this.$t('Track name')],
['album__title', 'Album name'], ['album__title', this.$t('Album name')],
['artist__name', 'Artist name'] ['artist__name', this.$t('Artist name')]
] ]
} }
}, },
......
<template> <template>
<button @click="$store.dispatch('favorites/toggle', track.id)" v-if="button" :class="['ui', 'pink', {'inverted': isFavorite}, {'favorited': isFavorite}, 'button']"> <button @click="$store.dispatch('favorites/toggle', track.id)" v-if="button" :class="['ui', 'pink', {'inverted': isFavorite}, {'favorited': isFavorite}, 'button']">
<i class="heart icon"></i> <i class="heart icon"></i>
<template v-if="isFavorite"> <i18next v-if="isFavorite" path="In favorites"/>
In favorites <i18next v-else path="Add to favorites"/>
</template>
<template v-else>
Add to favorites
</template>
</button> </button>
<i v-else @click="$store.dispatch('favorites/toggle', track.id)" :class="['favorite-icon', 'heart', {'pink': isFavorite}, {'favorited': isFavorite}, 'link', 'icon']" :title="title"></i> <i v-else @click="$store.dispatch('favorites/toggle', track.id)" :class="['favorite-icon', 'heart', {'pink': isFavorite}, {'favorited': isFavorite}, 'link', 'icon']" :title="title"></i>
</template> </template>
...@@ -20,9 +16,9 @@ export default { ...@@ -20,9 +16,9 @@ export default {
computed: { computed: {
title () { title () {
if (this.isFavorite) { if (this.isFavorite) {
return 'Remove from favorites' return this.$t('Remove from favorites')
} else { } else {
return 'Add to favorites' return this.$t('Add to favorites')
} }
}, },
isFavorite () { isFavorite () {
......
...@@ -2,32 +2,26 @@ ...@@ -2,32 +2,26 @@
<div> <div>
<div v-if="stats" class="ui stackable two column grid"> <div v-if="stats" class="ui stackable two column grid">
<div class="column"> <div class="column">
<h3 class="ui left aligned header">User activity</h3> <h3 class="ui left aligned header"><i18next path="User activity"/></h3>
<div class="ui mini horizontal statistics"> <div class="ui mini horizontal statistics">
<div class="statistic"> <div class="statistic">
<div class="value"> <div class="value">
<i class="green user icon"></i> <i class="green user icon"></i>
{{ stats.users }} {{ stats.users }}
</div> </div>
<div class="label"> <i18next tag="div" class="label" path="users"/>
Users
</div>
</div> </div>
<div class="statistic"> <div class="statistic">
<div class="value"> <div class="value">
<i class="orange sound icon"></i> {{ stats.listenings }} <i class="orange sound icon"></i> {{ stats.listenings }}
</div> </div>
<div class="label"> <i18next tag="div" class="label" path="tracks listened"/>
tracks listened
</div>
</div> </div>
<div class="statistic"> <div class="statistic">
<div class="value"> <div class="value">
<i class="pink heart icon"></i> {{ stats.track_favorites }} <i class="pink heart icon"></i> {{ stats.track_favorites }}
</div> </div>
<div class="label"> <i18next tag="div" class="label" path="Tracks favorited"/>
Tracks favorited
</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -38,33 +32,25 @@ ...@@ -38,33 +32,25 @@
<div class="value"> <div class="value">
{{ parseInt(stats.music_duration) }} {{ parseInt(stats.music_duration) }}
</div> </div>
<div class="label"> <i18next tag="div" class="label" path="hours of music"/>
hours of music
</div>
</div> </div>
<div class="statistic"> <div class="statistic">
<div class="value"> <div class="value">
{{ stats.artists }} {{ stats.artists }}
</div> </div>
<div class="label"> <i18next tag="div" class="label" path="Artists"/>
Artists
</div>
</div> </div>
<div class="statistic"> <div class="statistic">
<div class="value"> <div class="value">
{{ stats.albums }} {{ stats.albums }}
</div> </div>
<div class="label"> <i18next tag="div" class="label" path="Albums"/>
Albums
</div>
</div> </div>
<div class="statistic"> <div class="statistic">
<div class="value"> <div class="value">
{{ stats.tracks }} {{ stats.tracks }}
</div> </div>
<div class="label"> <i18next tag="div" class="label" path="tracks"/>
tracks
</div>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<a :href="getMusicbrainzUrl('artist', metadata.id)" target="_blank" title="View on MusicBrainz">{{ metadata.name }}</a> <a :href="getMusicbrainzUrl('artist', metadata.id)" target="_blank" title="View on MusicBrainz">{{ metadata.name }}</a>
</h3> </h3>
<form class="ui form" @submit.prevent=""> <form class="ui form" @submit.prevent="">
<h6 class="ui header">Filter album types</h6> <h6 class="ui header"><i18next path="Filter album types"/></h6>
<div class="inline fields"> <div class="inline fields">
<div class="field" v-for="t in availableReleaseTypes"> <div class="field" v-for="t in availableReleaseTypes">
<div class="ui checkbox"> <div class="ui checkbox">
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
</div> </div>
</div> </div>
<div class="field"> <div class="field">
<label>Query template</label> <i18next tag="label" path="Query template"/>
<input v-model="customQueryTemplate" /> <input v-model="customQueryTemplate" />
</div> </div>
</div> </div>
...@@ -53,8 +53,8 @@ export default Vue.extend({ ...@@ -53,8 +53,8 @@ export default Vue.extend({
releaseImportData: [], releaseImportData: [],
releaseGroupsData: {}, releaseGroupsData: {},
releases: [], releases: [],
releaseTypes: ['Album'], releaseTypes: [this.$t('Album')],
availableReleaseTypes: ['Album', 'Live', 'Compilation', 'EP', 'Single', 'Other'] availableReleaseTypes: [this.$t('Album'), this.$t('Live'), this.$t('Compilation'), this.$t('EP'), this.$t('Single'), this.$t('Other')]
} }
}, },
created () { created () {
......
...@@ -20,11 +20,11 @@ ...@@ -20,11 +20,11 @@
<table class="ui unstackable table"> <table class="ui unstackable table">
<thead> <thead>
<tr> <tr>
<th>Job ID</th> <i18next tag="th" path="Job ID"/>
<th>Recording MusicBrainz ID</th> <i18next tag="th" path="Recording MusicBrainz ID"/>
<th>Source</th> <i18next tag="th" path="Source"/>
<th>Status</th> <i18next tag="th" path="Status"/>
<th>Track</th> <i18next tag="th" path="Track"/>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
......
...@@ -5,20 +5,20 @@ ...@@ -5,20 +5,20 @@
<button <button
class="ui left floated labeled icon button" class="ui left floated labeled icon button"
@click="fetchData(previousLink)" @click="fetchData(previousLink)"
:disabled="!previousLink"><i class="left arrow icon"></i> Previous</button> :disabled="!previousLink"><i class="left arrow icon"></i><i18next path="Previous"/></button>
<button <button
class="ui right floated right labeled icon button" class="ui right floated right labeled icon button"
@click="fetchData(nextLink)" @click="fetchData(nextLink)"
:disabled="!nextLink">Next <i class="right arrow icon"></i></button> :disabled="!nextLink"><i18next path="Next"/><i class="right arrow icon"></i></button>
<div class="ui hidden clearing divider"></div> <div class="ui hidden clearing divider"></div>
<div class="ui hidden clearing divider"></div> <div class="ui hidden clearing divider"></div>
<table v-if="results.length > 0" class="ui unstackable table"> <table v-if="results.length > 0" class="ui unstackable table">
<thead> <thead>
<tr> <tr>
<th>ID</th> <i18next tag="th" path="ID"/>
<th>Launch date</th> <i18next tag="th" path="Launch date"/>
<th>Jobs</th> <i18next tag="th" path="Jobs"/>
<th>Status</th> <i18next tag="th" path="Status"/>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
......
...@@ -17,29 +17,31 @@ ...@@ -17,29 +17,31 @@
@input-file="inputFile" @input-file="inputFile"
ref="upload"> ref="upload">
<i class="upload icon"></i> <i class="upload icon"></i>
Select files to upload... <i18next path="Select files to upload..."/>
</file-upload-widget> </file-upload-widget>
<button <button
:class="['ui', 'right', 'floated', 'icon', {disabled: files.length === 0}, 'button']" :class="['ui', 'right', 'floated', 'icon', {disabled: files.length === 0}, 'button']"
v-if="!$refs.upload || !$refs.upload.active" @click.prevent="$refs.upload.active = true"> v-if="!$refs.upload || !$refs.upload.active" @click.prevent="$refs.upload.active = true">
<i class="play icon" aria-hidden="true"></i> <i class="play icon" aria-hidden="true"></i>
Start Upload <i18next path="Start Upload"/>
</button> </button>
<button type="button" class="ui right floated icon yellow button" v-else @click.prevent="$refs.upload.active = false"> <button type="button" class="ui right floated icon yellow button" v-else @click.prevent="$refs.upload.active = false">
<i class="pause icon" aria-hidden="true"></i> <i class="pause icon" aria-hidden="true"></i>
Stop Upload <i18next path="Stop Upload"/>
</button> </button>
</div> </div>
<div class="ui hidden clearing divider"></div> <div class="ui hidden clearing divider"></div>
<p v-if="batch"> <i18next v-if="batch" path="Once all your files are uploaded, simply head over {%0%} to check the import status.">
Once all your files are uploaded, simply head over <router-link :to="{name: 'library.import.batches.detail', params: {id: batch.id }}">import detail page</router-link> to check the import status. <router-link :to="{name: 'library.import.batches.detail', params: {id: batch.id }}">
</p> <i18next path="import detail page"/>
</router-link>
</i18next>
<table class="ui single line table"> <table class="ui single line table">
<thead> <thead>
<tr> <tr>
<th>File name</th> <i18next tag="th" path="File name"/>
<th>Size</th> <i18next tag="th" path="Size"/>
<th>Status</th> <i18next tag="th" path="Status"/>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
...@@ -50,10 +52,10 @@ ...@@ -50,10 +52,10 @@
<span v-if="file.error" class="ui red label"> <span v-if="file.error" class="ui red label">
{{ file.error }} {{ file.error }}
</span> </span>
<span v-else-if="file.success" class="ui green label">Success</span> <i18next v-else-if="file.success" class="ui green label" path="Success"/>
<span v-else-if="file.active" class="ui yellow label">Uploading...</span> <i18next v-else-if="file.active" class="ui yellow label" path="Uploading..."/>
<template v-else> <template v-else>
<span class="ui label">Pending</span> <i18next class="ui label" path="Pending"/>
<button class="ui tiny basic red icon button" @click.prevent="$refs.upload.remove(file)"><i class="delete icon"></i></button> <button class="ui tiny basic red icon button" @click.prevent="$refs.upload.remove(file)"><i class="delete icon"></i></button>
</template> </template>
</td> </td>
......
...@@ -4,45 +4,47 @@ ...@@ -4,45 +4,47 @@
<div class="ui top three attached ordered steps"> <div class="ui top three attached ordered steps">
<a @click="currentStep = 0" :class="['step', {'active': currentStep === 0}, {'completed': currentStep > 0}]"> <a @click="currentStep = 0" :class="['step', {'active': currentStep === 0}, {'completed': currentStep > 0}]">
<div class="content"> <div class="content">
<div class="title">Import source</div> <i18next tag="div" class="title" path="Import source"/>
<div class="description"> <i18next tag="div" class="description" path="Uploaded files or external source"/>
Uploaded files or external source
</div>
</div> </div>
</a> </a>
<a @click="currentStep = 1" :class="['step', {'active': currentStep === 1}, {'completed': currentStep > 1}]"> <a @click="currentStep = 1" :class="['step', {'active': currentStep === 1}, {'completed': currentStep > 1}]">
<div class="content"> <div class="content">
<div class="title">Metadata</div> <i18next tag="div" class="title" path="Metadata"/>
<div class="description">Grab corresponding metadata</div> <i18next tag="div" class="description" path="Grab corresponding metadata"/>
</div> </div>
</a> </a>
<a @click="currentStep = 2" :class="['step', {'active': currentStep === 2}, {'completed': currentStep > 2}]"> <a @click="currentStep = 2" :class="['step', {'active': currentStep === 2}, {'completed': currentStep > 2}]">
<div class="content"> <div class="content">
<div class="title">Music</div> <i18next tag="div" class="title" path="Music"/>
<div class="description">Select relevant sources or files for import</div> <i18next tag="div" class="description" path="Select relevant sources or files for import"/>
</div> </div>
</a> </a>
</div> </div>
<div class="ui hidden divider"></div> <div class="ui hidden divider"></div>
<div class="ui centered buttons"> <div class="ui centered buttons">
<button @click="currentStep -= 1" :disabled="currentStep === 0" class="ui icon button"><i class="left arrow icon"></i> Previous step</button> <button @click="currentStep -= 1" :disabled="currentStep === 0" class="ui icon button"><i class="left arrow icon"></i><i18next path="Previous step"/></button>
<button @click="currentStep += 1" v-if="currentStep < 2" class="ui icon button">Next step <i class="right arrow icon"></i></button> <button @click="currentStep += 1" v-if="currentStep < 2" class="ui icon button"><i18next path="Next step"/><i class="right arrow icon"></i></button>
<button <button
@click="$refs.import.launchImport()" @click="$refs.import.launchImport()"
v-if="currentStep === 2" v-if="currentStep === 2"
:class="['ui', 'positive', 'icon', {'loading': isImporting}, 'button']" :class="['ui', 'positive', 'icon', {'loading': isImporting}, 'button']"
:disabled="isImporting || importData.count === 0" :disabled="isImporting || importData.count === 0"
>Import {{ importData.count }} tracks <i class="check icon"></i></button> >
<i18next path="Import {%0%} tracks">{{ importData.count }}</i18next>
<i class="check icon"></i>
</button>
</div> </div>
<div class="ui hidden divider"></div> <div class="ui hidden divider"></div>
<div class="ui attached segment"> <div class="ui attached segment">
<template v-if="currentStep === 0"> <template v-if="currentStep === 0">
<p>First, choose where you want to import the music from :</p> <i18next tag="p" path="First, choose where you want to import the music from:"/>
<form class="ui form"> <form class="ui form">
<div class="field"> <div class="field">
<div class="ui radio checkbox"> <div class="ui radio checkbox">
<input type="radio" id="external" value="external" v-model="currentSource"> <input type="radio" id="external" value="external" v-model="currentSource">
<label for="external">External source. Supported backends: <label for="external">
<i18next path="External source. Supported backends:"/>
<div v-for="backend in backends" class="ui basic label"> <div v-for="backend in backends" class="ui basic label">
<i v-if="backend.icon" :class="[backend.icon, 'icon']"></i> <i v-if="backend.icon" :class="[backend.icon, 'icon']"></i>
{{ backend.label }} {{ backend.label }}
...@@ -53,7 +55,7 @@ ...@@ -53,7 +55,7 @@
<div class="field"> <div class="field">
<div class="ui radio checkbox"> <div class="ui radio checkbox">
<input type="radio" id="upload" value="upload" v-model="currentSource"> <input type="radio" id="upload" value="upload" v-model="currentSource">
<label for="upload">File upload</label> <i18next tag="label" for="upload" path="File upload" />
</div> </div>
</div> </div>
</form> </form>
...@@ -62,7 +64,7 @@ ...@@ -62,7 +64,7 @@
<div class="column"> <div class="column">
<form class="ui form" @submit.prevent=""> <form class="ui form" @submit.prevent="">
<div class="field"> <div class="field">
<label>Search an entity you want to import:</label> <i18next tag="label" path="Search an entity you want to import:"/>
<metadata-search <metadata-search
:mb-type="mbType" :mb-type="mbType"
:mb-id="mbId" :mb-id="mbId"
...@@ -70,29 +72,29 @@ ...@@ -70,29 +72,29 @@
@type-changed="updateType"></metadata-search> @type-changed="updateType"></metadata-search>
</div> </div>
</form> </form>
<div class="ui horizontal divider"> <i18next tag="div" class="ui horizontal divider" path="Or"/>
Or
</div>
<form class="ui form" @submit.prevent=""> <form class="ui form" @submit.prevent="">
<div class="field"> <div class="field">
<label>Input a MusicBrainz ID manually:</label> <i18next tag="label" path="Input a MusicBrainz ID manually:"/>
<input type="text" v-model="currentId" /> <input type="text" v-model="currentId" />
</div> </div>
</form> </form>
<div class="ui hidden divider"></div> <div class="ui hidden divider"></div>
<template v-if="currentType && currentId"> <template v-if="currentType && currentId">
<h4 class="ui header">You will import:</h4> <h4 class="ui header"><i18next path="You will import:"/></h4>
<component <component
:mbId="currentId" :mbId="currentId"
:is="metadataComponent" :is="metadataComponent"
@metadata-changed="this.updateMetadata" @metadata-changed="this.updateMetadata"
></component> ></component>
</template> </template>
<p>You can also skip this step and enter metadata manually.</p> <i18next tag="p" path="You can also skip this step and enter metadata manually."/>
</div> </div>
<div class="column"> <div class="column">
<h5 class="ui header">What is metadata?</h5> <h5 class="ui header">What is metadata?</h5>
<p>Metadata is the data related to the music you want to import. This includes all the information about the artists, albums and tracks. In order to have a high quality library, it is recommended to grab data from the <a href="http://musicbrainz.org/" target="_blank">MusicBrainz project</a>, which you can think about as the Wikipedia of music.</p> <i18next tag="p" path="Metadata is the data related to the music you want to import. This includes all the information about the artists, albums and tracks. In order to have a high quality library, it is recommended to grab data from the {%0%} project, which you can think about as the Wikipedia of music.">
<a href="http://musicbrainz.org/" target="_blank">MusicBrainz</a>
</i18next>
</div> </div>
</div> </div>
<div v-if="currentStep === 2"> <div v-if="currentStep === 2">
...@@ -116,8 +118,8 @@ ...@@ -116,8 +118,8 @@
</div> </div>
</div> </div>
<div class="ui vertical stripe segment" v-if="currentRequest"> <div class="ui vertical stripe segment" v-if="currentRequest">
<h3 class="ui header">Music request</h3> <h3 class="ui header"><i18next path="Music request"/></h3>
<p>This import will be associated with the music request below. After the import is finished, the request will be marked as fulfilled.</p> <i18next tag="p" path="This import will be associated with the music request below. After the import is finished, the request will be marked as fulfilled."/>
<request-card :request="currentRequest" :import-action="false"></request-card> <request-card :request="currentRequest" :import-action="false"></request-card>
</div> </div>
......
<template> <template>
<div> <div>
<h3 class="ui dividing block header"> <h3 class="ui dividing block header">
Album <a :href="getMusicbrainzUrl('release', metadata.id)" target="_blank" title="View on MusicBrainz">{{ metadata.title }}</a> ({{ tracks.length}} tracks) by <i18next path="Album {%0%} ({%1%} tracks) by {%2%}">
<a :href="getMusicbrainzUrl('release', metadata.id)" target="_blank" title="View on MusicBrainz">{{ metadata.title }}</a>
({{ tracks.length}} tracks)
<a :href="getMusicbrainzUrl('artist', metadata['artist-credit'][0]['artist']['id'])" target="_blank" title="View on MusicBrainz">{{ metadata['artist-credit-phrase'] }}</a> <a :href="getMusicbrainzUrl('artist', metadata['artist-credit'][0]['artist']['id'])" target="_blank" title="View on MusicBrainz">{{ metadata['artist-credit-phrase'] }}</a>
</i18next>
<div class="ui divider"></div> <div class="ui divider"></div>
<div class="sub header"> <div class="sub header">
<div class="ui toggle checkbox"> <div class="ui toggle checkbox">
<input type="checkbox" v-model="enabled" /> <input type="checkbox" v-model="enabled" />
<label>Import this release</label> <i18next tag="label" path="Import this release"/>
</div> </div>
</div> </div>
</h3> </h3>
......
...@@ -9,13 +9,13 @@ ...@@ -9,13 +9,13 @@
</h5> </h5>
<div class="ui toggle checkbox"> <div class="ui toggle checkbox">
<input type="checkbox" v-model="enabled" /> <input type="checkbox" v-model="enabled" />
<label>Import this track</label> <i18next tag="label" path="Import this track"/>
</div> </div>
</div> </div>
<div class="three wide column" v-if="enabled"> <div class="three wide column" v-if="enabled">
<form class="ui mini form" @submit.prevent=""> <form class="ui mini form" @submit.prevent="">
<div class="field"> <div class="field">
<label>Source</label> <i18next tag="label" path="Source"/>
<select v-model="currentBackendId"> <select v-model="currentBackendId">
<option v-for="backend in backends" :value="backend.id"> <option v-for="backend in backends" :value="backend.id">
{{ backend.label }} {{ backend.label }}
...@@ -28,7 +28,10 @@ ...@@ -28,7 +28,10 @@
<button @click="currentResultIndex -= 1" class="ui basic tiny icon button" :disabled="currentResultIndex === 0"> <button @click="currentResultIndex -= 1" class="ui basic tiny icon button" :disabled="currentResultIndex === 0">
<i class="left arrow icon"></i> <i class="left arrow icon"></i>
</button> </button>
Result {{ currentResultIndex + 1 }}/{{ results.length }} <i18next path="Result {%0%}/{%1%}">
{{ currentResultIndex + 1 }}
{{ results.length }}
</i18next>
<button @click="currentResultIndex += 1" class="ui basic tiny icon button" :disabled="currentResultIndex + 1 === results.length"> <button @click="currentResultIndex += 1" class="ui basic tiny icon button" :disabled="currentResultIndex + 1 === results.length">
<i class="right arrow icon"></i> <i class="right arrow icon"></i>
</button> </button>
...@@ -37,9 +40,9 @@ ...@@ -37,9 +40,9 @@
<div class="four wide column" v-if="enabled"> <div class="four wide column" v-if="enabled">
<form class="ui mini form" @submit.prevent=""> <form class="ui mini form" @submit.prevent="">
<div class="field"> <div class="field">
<label>Search query</label> <i18next tag="label" path="Search query"/>
<input type="text" v-model="query" /> <input type="text" v-model="query" />
<label>Imported URL</label> <i18next tag="label" path="Imported URL"/>
<input type="text" v-model="importedUrl" /> <input type="text" v-model="importedUrl" />
</div> </div>
</form> </form>
......
...@@ -11,6 +11,9 @@ import router from './router' ...@@ -11,6 +11,9 @@ import router from './router'
import axios from 'axios' import axios from 'axios'
import {VueMasonryPlugin} from 'vue-masonry' import {VueMasonryPlugin} from 'vue-masonry'
import VueLazyload from 'vue-lazyload' import VueLazyload from 'vue-lazyload'
import i18next from 'i18next'
import i18nextFetch from 'i18next-fetch-backend'
import VueI18Next from '@panter/vue-i18next'
import store from './store' import store from './store'
import config from './config' import config from './config'
import { sync } from 'vuex-router-sync' import { sync } from 'vuex-router-sync'
...@@ -27,6 +30,7 @@ window.$ = window.jQuery = require('jquery') ...@@ -27,6 +30,7 @@ window.$ = window.jQuery = require('jquery')
require('semantic-ui-css/semantic.js') require('semantic-ui-css/semantic.js')
require('masonry-layout') require('masonry-layout')
Vue.use(VueI18Next)
Vue.use(VueMasonryPlugin) Vue.use(VueMasonryPlugin)
Vue.use(VueLazyload) Vue.use(VueLazyload)
Vue.config.productionTip = false Vue.config.productionTip = false
...@@ -71,17 +75,36 @@ axios.interceptors.response.use(function (response) { ...@@ -71,17 +75,36 @@ axios.interceptors.response.use(function (response) {
} }
} }
if (error.backendErrors.length === 0) { if (error.backendErrors.length === 0) {
error.backendErrors.push('An unknown error occured, ensure your are connected to the internet and your funkwhale instance is up and running') error.backendErrors.push(i18next.t('An unknown error occured, ensure your are connected to the internet and your funkwhale instance is up and running'))
} }
// Do something with response error // Do something with response error
return Promise.reject(error) return Promise.reject(error)
}) })
store.dispatch('auth/check') store.dispatch('auth/check')
// i18n
i18next
.use(i18nextFetch)
.init({
lng: navigator.language,
fallbackLng: ['en'],
preload: [navigator.language, 'en'],
backend: {
loadPath: '/static/translations/{%lng%}.json'
},
interpolation: {
prefix: '{%',
suffix: '%}'
}
})
const i18n = new VueI18Next(i18next)
/* eslint-disable no-new */ /* eslint-disable no-new */
new Vue({ new Vue({
el: '#app', el: '#app',
router, router,
store, store,
i18n,
template: '<App/>', template: '<App/>',
components: { App } components: { App }
}) })
......
This diff is collapsed.
msgid ""
msgstr ""
"Project-Id-Version: Funkwhale 0.8\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-03-23 15:49-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
msgid "An unknown error occured, ensure your are connected to the internet and your funkwhale instance is up and running"
msgstr "An unknown error occured, ensure your are connected to the internet and your funkwhale instance is up and running"
msgid "Links"
msgstr "Links"
msgid "About this instance"
msgstr "About this instance"
msgid "Official website"
msgstr "Official website"
msgid "Source code"
msgstr "Source code"
msgid "Issue tracker"
msgstr "Issue tracker"
msgid "About funkwhale"
msgstr "About funkwhale"
msgid "Funkwhale is a free and open-source project run by volunteers. You can help us improve the platform by reporting bugs, suggesting features and share the project with your friends!"
msgstr "Funkwhale is a free and open-source project run by volunteers. You can help us improve the platform by reporting bugs, suggesting features and share the project with your friends!"
msgid "The funkwhale logo was kindly designed and provided by Francis Gading."
msgstr "The funkwhale logo was kindly designed and provided by Francis Gading."
msgid "{%0%} favorited a track {%1%}"
msgstr "{%0%} favorited a track {%1%}"
msgid "from album {%0%}, by {%1%}"
msgstr "from album {%0%}, by {%1%}"
msgid ", by {%0%}"
msgstr ", by {%0%}"
msgid "{%0%} listened to a track {%1%}"
msgstr "{%0%} listened to a track {%1%}"
msgid "Show {%0%} more tracks"
msgstr "Show {%0%} more tracks"
msgid "Collapse"
msgstr "Collapse"
msgid "Play all"
msgstr "Play all"
msgid "{%0%} tracks"
msgstr "{%0%} tracks"
msgid "Show {%0%} more albums"
msgstr "Show {%0%} more albums"
msgid "Title"
msgstr "Title"
msgid "Artist"
msgstr "Artist"
msgid "Album"
msgstr "Album"
msgid "Download..."
msgstr "Download..."
msgid "Download tracks"
msgstr "Download tracks"
msgid "There is currently no way to download directly multiple tracks from funkwhale as a ZIP archive. However, you can use a command line tools such as {%0%} to easily download a list of tracks."
msgstr "There is currently no way to download directly multiple tracks from funkwhale as a ZIP archive. However, you can use a command line tools such as {%0%} to easily download a list of tracks."
msgid "Simply copy paste the snippet below into a terminal to launch the download."
msgstr "Simply copy paste the snippet below into a terminal to launch the download."
msgid "Keep your PRIVATE_TOKEN secret as it gives access to your account."
msgstr "Keep your PRIVATE_TOKEN secret as it gives access to your account."
msgid "Cancel"
msgstr "Cancel"
msgid "Add to current queue"
msgstr "Add to current queue"
msgid "Play"
msgstr "Play"
msgid "Add to queue"
msgstr "Add to queue"
msgid "Play next"
msgstr "Play next"
msgid "Play now"
msgstr "Play now"
msgid "Previous track"
msgstr "Previous track"
msgid "Play track"
msgstr "Play track"
msgid "Pause track"
msgstr "Pause track"
msgid "Next track"
msgstr "Next track"
msgid "Unmute"
msgstr "Unmute"
msgid "Mute"
msgstr "Mute"
msgid "Looping disabled. Click to switch to single-track looping."
msgstr "Looping disabled. Click to switch to single-track looping."
msgid "Looping on a single track. Click to switch to whole queue looping."
msgstr "Looping on a single track. Click to switch to whole queue looping."
msgid "Looping on whole queue. Click to disable looping."
msgstr "Looping on whole queue. Click to disable looping."
msgid "Shuffle your queue"
msgstr "Shuffle your queue"
msgid "Clear your queue"
msgstr "Clear your queue"
msgid "Search for some music"
msgstr "Search for some music"
msgid "Artists"
msgstr "Artists"
msgid "Sorry, we did not found any artist matching your query"
msgstr "Sorry, we did not found any artist matching your query"
msgid "Albums"
msgstr "Albums"
msgid "Sorry, we did not found any album matching your query"
msgstr "Sorry, we did not found any album matching your query"
msgid "Log in to your Funkwhale account"
msgstr "Log in to your Funkwhale account"
msgid "We cannot log you in"
msgstr "We cannot log you in"
msgid "Please double-check your username/password couple is correct"
msgstr "Please double-check your username/password couple is correct"
msgid "An unknown error happend, this can mean the server is down or cannot be reached"
msgstr "An unknown error happend, this can mean the server is down or cannot be reached"
msgid "Username or email"
msgstr "Username or email"
msgid "Password"
msgstr "Password"
msgid "Login"
msgstr "Login"
msgid "Create an account"
msgstr "Create an account"
msgid "Are you sure you want to log out?"
msgstr "Are you sure you want to log out?"
msgid "You are currently logged in as {%0%}"
msgstr "You are currently logged in as {%0%}"
msgid "Yes, log me out!"
msgstr "Yes, log me out!"
msgid "Registered since {%0%}"
msgstr "Registered since {%0%}"
msgid "This is you!"
msgstr "This is you!"
msgid "Staff member"
msgstr "Staff member"
msgid "Settings..."
msgstr "Settings..."
msgid "Account settings"
msgstr "Account settings"
msgid "Settings updated"
msgstr "Settings updated"
msgid "We cannot save your settings"
msgstr "We cannot save your settings"
msgid "Update settings"
msgstr "Update settings"
msgid "Change my password"
msgstr "Change my password"
msgid "Cannot change your password"
msgstr "Cannot change your password"
msgid "Please double-check your password is correct"
msgstr "Please double-check your password is correct"
msgid "Old password"
msgstr "Old password"
msgid "New password"
msgid "New password"
msgid "Change password"
msgstr "Change password"
msgid "Activity visibility"
msgstr "Activity visibility"
msgid "Determine the visibility level of your activity"
msgstr "Determine the visibility level of your activity"
msgid "Nobody except me"
msgstr "Nobody except me"
msgid "Everyone on this instance"
msgstr "Everyone on this instance"
msgid "Create a funkwhale account"
msgstr "Create a funkwhale account"
msgid "We cannot create your account"
msgstr "We cannot create your account"
msgid "Username"
msgstr "Username"
msgid "Email"
msgstr "Email"
msgid "Create my account"
msgstr "Create my account"
msgid "Registration is currently disabled on this instance, please try again later."
msgstr "Registration is currently disabled on this instance, please try again later."
msgid "Do you want to confirm this action?"
msgstr "Do you want to confirm this action?"
msgid "Confirm"
msgstr "Confirm"
msgid "Expand"
msgstr "Expand"
msgid "Loading your favorites..."
msgstr "Loading your favorites..."
msgid "{%0%} favorites"
msgstr "{%0%} favorites"
msgid "Ordering"
msgstr "Ordering"
msgid "Ordering direction"
msgstr "Ordering direction"
msgid "Ascending"
msgstr "Ascending"
msgid "Descending"
msgstr "Descending"
msgid "Results per page"
msgstr "Results per page"
msgid "Track name"
msgstr "Track name"
msgid "Album name"
msgstr "Album name"
msgid "Artist name"
msgstr "Artist name"
msgid "In favorites"
msgstr "In favorites"
msgid "Add to favorites"
msgstr "Add to favorites"
msgid "Remove from favorites"
msgstr "Remove from favorites"
msgid "User activity"
msgstr "User activity"
msgid "users"
msgstr "users"
msgid "tracks listened"
msgstr "tracks listened"
msgid "Tracks favorited"
msgstr "Tracks favorited"
msgid "hours of music"
msgstr "hours of music"
msgid "Artists"
msgstr "Artists"
msgid "Albums"
msgstr "Albums"
msgid "tracks"
msgstr "tracks"
msgid "Filter album types"
msgstr "Filter album types"
msgid "Query template"
msgstr "Query template"
msgid "Live"
msgstr "Live"
msgid "Compilation"
msgstr "Compilation"
msgid "EP"
msgstr "EP"
msgid "Single"
msgstr "Single"
msgid "Other"
msgstr "Other"
msgid "Job ID"
msgstr "Job ID"
msgid "Recording MusicBrainz ID"
msgstr "Recording MusicBrainz ID"
msgid "Source"
msgstr "Source"
msgid "Track"
msgstr "Track"
msgid "Previous"
msgstr "Previous"
msgid "Next"
msgstr "Next"
msgid "ID"
msgstr "ID"
msgid "Launch date"
msgstr "Launch date"
msgid "Jobs"
msgstr "Jobs"
msgid "Status"
msgstr "Status"
msgid "Select files to upload..."
msgstr "Select files to upload..."
msgid "Start Upload"
msgstr "Start Upload"
msgid "Stop Upload"
msgstr "Stop Upload"
msgid "Once all your files are uploaded, simply head over {%0%} to check the import status."
msgstr "Once all your files are uploaded, simply head over {%0%} to check the import status."
msgid "import detail page"
msgstr "import detail page"
msgid "File name"
msgstr "File name"
msgid "Size"
msgstr "Size"
msgid "Success"
msgstr "Success"
msgid "Uploading..."
msgstr "Uploading..."
msgid "Pending"
msgstr "Pending"
msgid "Import source"
msgstr "Import source"
msgid "Uploaded files or external source"
msgstr "Uploaded files or external source"
msgid "Metadata"
msgstr "Metadata"
msgid "Grab corresponding metadata"
msgstr "Grab corresponding metadata"
msgid "Music"
msgstr "Music"
msgid "Select relevant sources or files for import"
msgstr "Select relevant sources or files for import"
msgid "Previous step"
msgstr "Previous step"
msgid "Next step"
msgstr "Next step"
msgid "Import {%0%} tracks"
msgstr "Import {%0%} tracks"
msgid "First, choose where you want to import the music from:"
msgstr "First, choose where you want to import the music from:"
msgid "External source. Supported backends:"
msgstr "External source. Supported backends:"
msgid "File upload"
msgstr "File upload"
msgid "Search an entity you want to import:"
msgstr "Search an entity you want to import:"
msgid "Input a MusicBrainz ID manually:"
msgstr "Input a MusicBrainz ID manually:"
msgid "Or"
msgstr "Or"
msgid "You will import:"
msgstr "You will import:"
msgid "You can also skip this step and enter metadata manually."
msgstr "You can also skip this step and enter metadata manually."
msgid "Metadata is the data related to the music you want to import. This includes all the information about the artists, albums and tracks. In order to have a high quality library, it is recommended to grab data from the {%0%} project, which you can think about as the Wikipedia of music."
msgstr "Metadata is the data related to the music you want to import. This includes all the information about the artists, albums and tracks. In order to have a high quality library, it is recommended to grab data from the {%0%} project, which you can think about as the Wikipedia of music."
msgid "Music request"
msgstr "Music request"
msgid "This import will be associated with the music request below. After the import is finished, the request will be marked as fulfilled."
msgstr "This import will be associated with the music request below. After the import is finished, the request will be marked as fulfilled."
msgid "Album {%0%} ({%1%} tracks) by {%2%}"
msgstr "Album {%0%} ({%1%} tracks) by {%2%}"
msgid "Import this release"
msgstr "Import this release"
msgid "Import this track"
msgstr "Import this track"
msgid "Source"
msgstr "Source"
msgid "Result {%0%}/{%1%}"
msgstr "Result {%0%}/{%1%}"
msgid "Search query"
msgstr "Search query"
msgid "Imported URL"
msgstr "Imported URL"
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment