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 !125
parents e608de2c 1341c9aa
No related branches found
No related tags found
No related merge requests found
Showing
with 185 additions and 112 deletions
...@@ -35,7 +35,6 @@ htmlcov ...@@ -35,7 +35,6 @@ htmlcov
# Translations # Translations
*.mo *.mo
*.pot
# Pycharm # Pycharm
.idea .idea
...@@ -75,6 +74,7 @@ api/static ...@@ -75,6 +74,7 @@ api/static
api/.pytest_cache api/.pytest_cache
# Front # Front
front/static/translations
front/node_modules/ front/node_modules/
front/dist/ front/dist/
front/npm-debug.log* front/npm-debug.log*
......
Add internationalization support (#5)
...@@ -13,6 +13,7 @@ services: ...@@ -13,6 +13,7 @@ services:
- "${WEBPACK_DEVSERVER_PORT-8080}:${WEBPACK_DEVSERVER_PORT-8080}" - "${WEBPACK_DEVSERVER_PORT-8080}:${WEBPACK_DEVSERVER_PORT-8080}"
volumes: volumes:
- './front:/app' - './front:/app'
- './po:/po'
postgres: postgres:
env_file: env_file:
......
...@@ -14,6 +14,8 @@ var webpackConfig = process.env.NODE_ENV === 'testing' ...@@ -14,6 +14,8 @@ var webpackConfig = process.env.NODE_ENV === 'testing'
? require('./webpack.prod.conf') ? require('./webpack.prod.conf')
: require('./webpack.dev.conf') : require('./webpack.dev.conf')
require('./i18n')
// default port where dev server listens for incoming traffic // default port where dev server listens for incoming traffic
var port = process.env.PORT || config.dev.port var port = process.env.PORT || config.dev.port
var host = process.env.HOST || config.dev.host var host = process.env.HOST || config.dev.host
......
const fs = require('fs');
const path = require('path');
const { gettextToI18next } = require('i18next-conv');
const poDir = path.join(__dirname, '..', '..', 'po')
const outDir = path.join(__dirname, '..', 'static', 'translations')
if (!fs.existsSync(outDir) || !fs.statSync(outDir).isDirectory()) {
fs.mkdirSync(outDir)
}
// Convert .po files to i18next files
fs.readdir(poDir, (err, files) => {
if (err) {
return console.log(err)
}
for (const file of files) {
if (file.endsWith('.po')) {
const lang = file.replace(/\.po$/, '')
const output = path.join(outDir, `${lang}.json`)
fs.readFile(path.join(poDir, file), (err, content) => {
if (err) {
return console.log(err)
}
gettextToI18next(lang, content).then(res => {
fs.writeFile(output, res, err => {
if (err) {
console.log(err)
} else {
console.log(`Wrote translation file: ${output}`)
}
})
})
})
}
}
})
...@@ -15,9 +15,13 @@ ...@@ -15,9 +15,13 @@
"lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs" "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs"
}, },
"dependencies": { "dependencies": {
"@panter/vue-i18next": "^0.9.1",
"axios": "^0.17.1", "axios": "^0.17.1",
"dateformat": "^2.0.0", "dateformat": "^2.0.0",
"django-channels": "^1.1.6", "django-channels": "^1.1.6",
"i18next": "^11.1.1",
"i18next-conv": "^6.0.0",
"i18next-fetch-backend": "^0.1.0",
"js-logger": "^1.3.0", "js-logger": "^1.3.0",
"jwt-decode": "^2.2.0", "jwt-decode": "^2.2.0",
"lodash": "^4.17.4", "lodash": "^4.17.4",
...@@ -34,7 +38,7 @@ ...@@ -34,7 +38,7 @@
"vue-upload-component": "^2.7.4", "vue-upload-component": "^2.7.4",
"vuedraggable": "^2.14.1", "vuedraggable": "^2.14.1",
"vuex": "^3.0.1", "vuex": "^3.0.1",
"vuex-persistedstate": "^2.4.2", "vuex-persistedstate": "^2.5.2",
"vuex-router-sync": "^5.0.0" "vuex-router-sync": "^5.0.0"
}, },
"devDependencies": { "devDependencies": {
......
...@@ -7,21 +7,25 @@ ...@@ -7,21 +7,25 @@
<div class="ui container"> <div class="ui container">
<div class="ui stackable equal height stackable grid"> <div class="ui stackable equal height stackable grid">
<div class="three wide column"> <div class="three wide column">
<h4 class="ui header">Links</h4> <i18next tag="h4" class="ui header" path="Links"></i18next>
<div class="ui link list"> <div class="ui link list">
<router-link class="item" to="/about"> <router-link class="item" to="/about">
About this instance <i18next path="About this instance" />
</router-link> </router-link>
<a href="https://funkwhale.audio" class="item" target="_blank">Official website</a> <i18next tag="a" href="https://funkwhale.audio" class="item" target="_blank" path="Official website" />
<a href="https://docs.funkwhale.audio" class="item" target="_blank">Documentation</a> <i18next tag="a" href="https://docs.funkwhale.audio" class="item" target="_blank" path="Documentation" />
<a href="https://code.eliotberriot.com/funkwhale/funkwhale" class="item" target="_blank">Source code</a> <i18next tag="a" href="https://code.eliotberriot.com/funkwhale/funkwhale" class="item" target="_blank" path="Source code" />
<a href="https://code.eliotberriot.com/funkwhale/funkwhale/issues" class="item" target="_blank">Issue tracker</a> <i18next tag="a" href="https://code.eliotberriot.com/funkwhale/funkwhale/issues" class="item" target="_blank" path="Issue tracker" />
</div> </div>
</div> </div>
<div class="ten wide column"> <div class="ten wide column">
<h4 class="ui header">About funkwhale</h4> <i18next tag="h4" class="ui header" path="About funkwhale" />
<p>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!</p> <p>
<p>The funkwhale logo was kindly designed and provided by Francis Gading.</p> <i18next path="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!"/>
</p>
<p>
<i18next path="The funkwhale logo was kindly designed and provided by Francis Gading."/>
</p>
</div> </div>
</div> </div>
</div> </div>
...@@ -31,7 +35,6 @@ ...@@ -31,7 +35,6 @@
:dsn="$store.state.instance.settings.raven.front_dsn.value"> :dsn="$store.state.instance.settings.raven.front_dsn.value">
</raven> </raven>
<playlist-modal v-if="$store.state.auth.authenticated"></playlist-modal> <playlist-modal v-if="$store.state.auth.authenticated"></playlist-modal>
</div> </div>
</template> </template>
......
...@@ -5,17 +5,20 @@ ...@@ -5,17 +5,20 @@
</div> </div>
<div class="content"> <div class="content">
<div class="summary"> <div class="summary">
<i18next path="{%0%} favorited a track {%1%}">
<slot name="user"></slot> <slot name="user"></slot>
favorited a track
<slot name="date"></slot> <slot name="date"></slot>
</i18next>
</div> </div>
<div class="extra text"> <div class="extra text">
<router-link :to="{name: 'library.tracks.detail', params: {id: event.object.local_id }}">{{ event.object.name }}</router-link> <router-link :to="{name: 'library.tracks.detail', params: {id: event.object.local_id }}">{{ event.object.name }}</router-link>
<template v-if="event.object.album">from album {{ event.object.album }}, by <em>{{ event.object.artist }}</em> <i18next path="from album {%0%}, by {%1%}" v-if="event.object.album">
</template> {{ event.object.album }}
<template v-else>, by <em>{{ event.object.artist }}</em> <em>{{ event.object.artist }}</em>
</template> </i18next>
<i18next path=", by {%0%}" v-else>
<em>{{ event.object.artist }}</em>
</i18next>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -5,17 +5,20 @@ ...@@ -5,17 +5,20 @@
</div> </div>
<div class="content"> <div class="content">
<div class="summary"> <div class="summary">
<i18next path="{%0%} listened to a track {%1%}">
<slot name="user"></slot> <slot name="user"></slot>
listened to a track
<slot name="date"></slot> <slot name="date"></slot>
</i18next>
</div> </div>
<div class="extra text"> <div class="extra text">
<router-link :to="{name: 'library.tracks.detail', params: {id: event.object.local_id }}">{{ event.object.name }}</router-link> <router-link :to="{name: 'library.tracks.detail', params: {id: event.object.local_id }}">{{ event.object.name }}</router-link>
<template v-if="event.object.album">from album {{ event.object.album }}, by <em>{{ event.object.artist }}</em> <i18next path="from album {%0%}, by {%1%}" v-if="event.object.album">
</template> {{ event.object.album }}
<template v-else>, by <em>{{ event.object.artist }}</em> <em>{{ event.object.artist }}</em>
</template> </i18next>
<i18next path=", by {%0%}" v-else>
<em>{{ event.object.artist }}</em>
</i18next>
</div> </div>
</div> </div>
</div> </div>
......
<template> <template>
<div :class="['ui', {'tiny': discrete}, 'buttons']"> <div :class="['ui', {'tiny': discrete}, 'buttons']">
<button <button
title="Add to current queue" :title="$t('Add to current queue')"
@click="add" @click="add"
:class="['ui', {loading: isLoading}, {'mini': discrete}, {disabled: !playable}, 'button']"> :class="['ui', {loading: isLoading}, {'mini': discrete}, {disabled: !playable}, 'button']">
<i class="ui play icon"></i> <i class="ui play icon"></i>
<template v-if="!discrete"><slot>Play</slot></template> <template v-if="!discrete"><slot><i18next path="Play"/></slot></template>
</button> </button>
<div v-if="!discrete" :class="['ui', {disabled: !playable}, 'floating', 'dropdown', 'icon', 'button']"> <div v-if="!discrete" :class="['ui', {disabled: !playable}, 'floating', 'dropdown', 'icon', 'button']">
<i class="dropdown icon"></i> <i class="dropdown icon"></i>
<div class="menu"> <div class="menu">
<div class="item"@click="add"><i class="plus icon"></i> Add to queue</div> <div class="item"@click="add"><i class="plus icon"></i><i18next path="Add to queue"/></div>
<div class="item"@click="addNext()"><i class="step forward icon"></i> Play next</div> <div class="item"@click="addNext()"><i class="step forward icon"></i><i18next path="Play next"/></div>
<div class="item"@click="addNext(true)"><i class="arrow down icon"></i> Play now</div> <div class="item"@click="addNext(true)"><i class="arrow down icon"></i><i18next path="Play now"/></div>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -57,44 +57,44 @@ ...@@ -57,44 +57,44 @@
<div class="two wide column controls ui grid"> <div class="two wide column controls ui grid">
<div <div
title="Previous track" :title="$t('Previous track')"
class="two wide column control" class="two wide column control"
:disabled="emptyQueue"> :disabled="emptyQueue">
<i @click="previous" :class="['ui', 'backward', {'disabled': emptyQueue}, 'big', 'icon']"></i> <i @click="previous" :class="['ui', 'backward', {'disabled': emptyQueue}, 'big', 'icon']"></i>
</div> </div>
<div <div
v-if="!playing" v-if="!playing"
title="Play track" :title="$t('Play track')"
class="two wide column control"> class="two wide column control">
<i @click="togglePlay" :class="['ui', 'play', {'disabled': !currentTrack}, 'big', 'icon']"></i> <i @click="togglePlay" :class="['ui', 'play', {'disabled': !currentTrack}, 'big', 'icon']"></i>
</div> </div>
<div <div
v-else v-else
title="Pause track" :title="$t('Pause track')"
class="two wide column control"> class="two wide column control">
<i @click="togglePlay" :class="['ui', 'pause', {'disabled': !currentTrack}, 'big', 'icon']"></i> <i @click="togglePlay" :class="['ui', 'pause', {'disabled': !currentTrack}, 'big', 'icon']"></i>
</div> </div>
<div <div
title="Next track" :title="$t('Next track')"
class="two wide column control" class="two wide column control"
:disabled="!hasNext"> :disabled="!hasNext">
<i @click="next" :class="['ui', {'disabled': !hasNext}, 'step', 'forward', 'big', 'icon']" ></i> <i @click="next" :class="['ui', {'disabled': !hasNext}, 'step', 'forward', 'big', 'icon']" ></i>
</div> </div>
<div class="two wide column control volume-control"> <div class="two wide column control volume-control">
<i title="Unmute" @click="$store.commit('player/volume', 1)" v-if="volume === 0" class="volume off secondary icon"></i> <i :title="$t('Unmute')" @click="$store.commit('player/volume', 1)" v-if="volume === 0" class="volume off secondary icon"></i>
<i title="Mute" @click="$store.commit('player/volume', 0)" v-else-if="volume < 0.5" class="volume down secondary icon"></i> <i :title="$t('Mute')" @click="$store.commit('player/volume', 0)" v-else-if="volume < 0.5" class="volume down secondary icon"></i>
<i title="Mute" @click="$store.commit('player/volume', 0)" v-else class="volume up secondary icon"></i> <i :title="$t('Mute')" @click="$store.commit('player/volume', 0)" v-else class="volume up secondary icon"></i>
<input type="range" step="0.05" min="0" max="1" v-model="sliderVolume" /> <input type="range" step="0.05" min="0" max="1" v-model="sliderVolume" />
</div> </div>
<div class="two wide column control looping"> <div class="two wide column control looping">
<i <i
title="Looping disabled. Click to switch to single-track looping." :title="$t('Looping disabled. Click to switch to single-track looping.')"
v-if="looping === 0" v-if="looping === 0"
@click="$store.commit('player/looping', 1)" @click="$store.commit('player/looping', 1)"
:disabled="!currentTrack" :disabled="!currentTrack"
:class="['ui', {'disabled': !currentTrack}, 'step', 'repeat', 'secondary', 'icon']"></i> :class="['ui', {'disabled': !currentTrack}, 'step', 'repeat', 'secondary', 'icon']"></i>
<i <i
title="Looping on a single track. Click to switch to whole queue looping." :title="$t('Looping on a single track. Click to switch to whole queue looping.')"
v-if="looping === 1" v-if="looping === 1"
@click="$store.commit('player/looping', 2)" @click="$store.commit('player/looping', 2)"
:disabled="!currentTrack" :disabled="!currentTrack"
...@@ -102,7 +102,7 @@ ...@@ -102,7 +102,7 @@
<span class="ui circular tiny orange label">1</span> <span class="ui circular tiny orange label">1</span>
</i> </i>
<i <i
title="Looping on whole queue. Click to disable looping." :title="$t('Looping on whole queue. Click to disable looping.')"
v-if="looping === 2" v-if="looping === 2"
@click="$store.commit('player/looping', 0)" @click="$store.commit('player/looping', 0)"
:disabled="!currentTrack" :disabled="!currentTrack"
...@@ -111,14 +111,14 @@ ...@@ -111,14 +111,14 @@
</div> </div>
<div <div
:disabled="queue.tracks.length === 0" :disabled="queue.tracks.length === 0"
title="Shuffle your queue" :title="$t('Shuffle your queue')"
class="two wide column control"> class="two wide column control">
<i @click="shuffle()" :class="['ui', 'random', 'secondary', {'disabled': queue.tracks.length === 0}, 'icon']" ></i> <i @click="shuffle()" :class="['ui', 'random', 'secondary', {'disabled': queue.tracks.length === 0}, 'icon']" ></i>
</div> </div>
<div class="one wide column"></div> <div class="one wide column"></div>
<div <div
:disabled="queue.tracks.length === 0" :disabled="queue.tracks.length === 0"
title="Clear your queue" :title="$t('Clear your queue')"
class="two wide column control"> class="two wide column control">
<i @click="clean()" :class="['ui', 'trash', 'secondary', {'disabled': queue.tracks.length === 0}, 'icon']" ></i> <i @click="clean()" :class="['ui', 'trash', 'secondary', {'disabled': queue.tracks.length === 0}, 'icon']" ></i>
</div> </div>
......
<template> <template>
<div> <div>
<h2>Search for some music</h2> <h2><i18next path="Search for some music"/></h2>
<div :class="['ui', {'loading': isLoading }, 'search']"> <div :class="['ui', {'loading': isLoading }, 'search']">
<div class="ui icon big input"> <div class="ui icon big input">
<i class="search icon"></i> <i class="search icon"></i>
...@@ -8,22 +8,22 @@ ...@@ -8,22 +8,22 @@
</div> </div>
</div> </div>
<template v-if="query.length > 0"> <template v-if="query.length > 0">
<h3 class="ui title">Artists</h3> <h3 class="ui title"><i18next path="Artists"/></h3>
<div v-if="results.artists.length > 0" class="ui stackable three column grid"> <div v-if="results.artists.length > 0" class="ui stackable three column grid">
<div class="column" :key="artist.id" v-for="artist in results.artists"> <div class="column" :key="artist.id" v-for="artist in results.artists">
<artist-card class="fluid" :artist="artist" ></artist-card> <artist-card class="fluid" :artist="artist" ></artist-card>
</div> </div>
</div> </div>
<p v-else>Sorry, we did not found any artist matching your query</p> <p v-else><i18next path="Sorry, we did not found any artist matching your query"/></p>
</template> </template>
<template v-if="query.length > 0"> <template v-if="query.length > 0">
<h3 class="ui title">Albums</h3> <h3 class="ui title"><i18next path="Albums"/></h3>
<div v-if="results.albums.length > 0" class="ui stackable three column grid"> <div v-if="results.albums.length > 0" class="ui stackable three column grid">
<div class="column" :key="album.id" v-for="album in results.albums"> <div class="column" :key="album.id" v-for="album in results.albums">
<album-card class="fluid" :album="album" ></album-card> <album-card class="fluid" :album="album" ></album-card>
</div> </div>
</div> </div>
<p v-else>Sorry, we did not found any album matching your query</p> <p v-else><i18next path="Sorry, we did not found any album matching your query"/></p>
</template> </template>
</div> </div>
</template> </template>
......
...@@ -10,8 +10,10 @@ ...@@ -10,8 +10,10 @@
</div> </div>
<div class="meta"> <div class="meta">
<span> <span>
By <router-link tag="span" :to="{name: 'library.artists.detail', params: {id: album.artist.id }}"> <i18next path="By {%0%}">
<router-link tag="span" :to="{name: 'library.artists.detail', params: {id: album.artist.id }}">
{{ album.artist.name }}</router-link> {{ album.artist.name }}</router-link>
</i18next>
</span><span class="time" v-if="album.release_date">{{ album.release_date | year }}</span> </span><span class="time" v-if="album.release_date">{{ album.release_date | year }}</span>
</div> </div>
<div class="description" v-if="mode === 'rich'"> <div class="description" v-if="mode === 'rich'">
...@@ -36,16 +38,24 @@ ...@@ -36,16 +38,24 @@
</tbody> </tbody>
</table> </table>
<div class="center aligned segment" v-if="album.tracks.length > initialTracks"> <div class="center aligned segment" v-if="album.tracks.length > initialTracks">
<em v-if="!showAllTracks" @click="showAllTracks = true" class="expand">Show {{ album.tracks.length - initialTracks }} more tracks</em> <em v-if="!showAllTracks" @click="showAllTracks = true" class="expand">
<em v-else @click="showAllTracks = false" class="expand">Collapse</em> <i18next path="Show {%0%} more tracks">{{ album.tracks.length - initialTracks }}</i18next>
</em>
<em v-else @click="showAllTracks = false" class="expand">
<i18next path="Collapse" />
</em>
</div> </div>
</div> </div>
</div> </div>
<div class="extra content"> <div class="extra content">
<play-button class="mini basic orange right floated" :tracks="album.tracks">Play all</play-button> <play-button class="mini basic orange right floated" :tracks="album.tracks">
<i18next path="Play all"/>
</play-button>
<span> <span>
<i class="music icon"></i> <i class="music icon"></i>
{{ album.tracks.length }} tracks <i18next path="{%0%} tracks">
{{ album.tracks.length }}
</i18next>
</span> </span>
</div> </div>
</div> </div>
......
...@@ -27,17 +27,27 @@ ...@@ -27,17 +27,27 @@
</tbody> </tbody>
</table> </table>
<div class="center aligned segment" v-if="artist.albums.length > initialAlbums"> <div class="center aligned segment" v-if="artist.albums.length > initialAlbums">
<em v-if="!showAllAlbums" @click="showAllAlbums = true" class="expand">Show {{ artist.albums.length - initialAlbums }} more albums</em> <em v-if="!showAllAlbums" @click="showAllAlbums = true" class="expand">
<em v-else @click="showAllAlbums = false" class="expand">Collapse</em> <i18next path="Show {%0%} more albums">
{{ artist.albums.length - initialAlbums }}
</i18next>
</em>
<em v-else @click="showAllAlbums = false" class="expand">
<i18next path="Collapse"/>
</em>
</div> </div>
</div> </div>
</div> </div>
<div class="extra content"> <div class="extra content">
<span> <span>
<i class="sound icon"></i> <i class="sound icon"></i>
{{ artist.albums.length }} albums <i18next path="{%0%} albums">
{{ artist.albums.length }}
</i18next>
</span> </span>
<play-button class="mini basic orange right floated" :tracks="allTracks">Play all</play-button> <play-button class="mini basic orange right floated" :tracks="allTracks">
<i18next path="Play all"/>
</play-button>
</div> </div>
</div> </div>
</template> </template>
......
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
<tr> <tr>
<th></th> <th></th>
<th></th> <th></th>
<th colspan="6">Title</th> <i18next tag="th" colspan="6" path="Title"/>
<th colspan="6">Artist</th> <i18next tag="th" colspan="6" path="Artist"/>
<th colspan="6">Album</th> <i18next tag="th" colspan="6" path="Album"/>
<th></th> <th></th>
</tr> </tr>
</thead> </thead>
...@@ -20,20 +20,18 @@ ...@@ -20,20 +20,18 @@
<tfoot class="full-width"> <tfoot class="full-width">
<tr> <tr>
<th colspan="3"> <th colspan="3">
<button @click="showDownloadModal = !showDownloadModal" class="ui basic button">Download...</button> <button @click="showDownloadModal = !showDownloadModal" class="ui basic button">
<i18next path="Download..."/>
</button>
<modal :show.sync="showDownloadModal"> <modal :show.sync="showDownloadModal">
<div class="header"> <i18next tag="div" path="Download tracks" class="header" />
Download tracks
</div>
<div class="content"> <div class="content">
<div class="description"> <div class="description">
<p>There is currently no way to download directly multiple tracks from funkwhale as a ZIP archive. <i18next tag="p" path="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.">
However, you can use a command line tools such as <a href="https://curl.haxx.se/" target="_blank">cURL</a> to easily download a list of tracks. <a href="https://curl.haxx.se/" target="_blank">cURL</a>
</p> </i18next>
<p>Simply copy paste the snippet below into a terminal to launch the download.</p> <i18next path="Simply copy paste the snippet below into a terminal to launch the download."/>
<div class="ui warning message"> <i18next tag="div" class="ui warning message" path="Keep your PRIVATE_TOKEN secret as it gives access to your account."/>
Keep your PRIVATE_TOKEN secret as it gives access to your account.
</div>
<pre> <pre>
export PRIVATE_TOKEN="{{ $store.state.auth.token }}" export PRIVATE_TOKEN="{{ $store.state.auth.token }}"
<template v-for="track in tracks"><template v-if="track.files.length > 0"> <template v-for="track in tracks"><template v-if="track.files.length > 0">
...@@ -42,9 +40,7 @@ curl -G -o "{{ track.files[0].filename }}" <template v-if="$store.state.auth.aut ...@@ -42,9 +40,7 @@ curl -G -o "{{ track.files[0].filename }}" <template v-if="$store.state.auth.aut
</div> </div>
</div> </div>
<div class="actions"> <div class="actions">
<div class="ui black deny button"> <i18next tag="div" class="ui black deny button" path="Cancel" />
Cancel
</div>
</div> </div>
</modal> </modal>
</th> </th>
......
...@@ -2,17 +2,17 @@ ...@@ -2,17 +2,17 @@
<div class="main pusher" v-title="'Log In'"> <div class="main pusher" v-title="'Log In'">
<div class="ui vertical stripe segment"> <div class="ui vertical stripe segment">
<div class="ui small text container"> <div class="ui small text container">
<h2>Log in to your Funkwhale account</h2> <h2><i18next path="Log in to your Funkwhale account"/></h2>
<form class="ui form" @submit.prevent="submit()"> <form class="ui form" @submit.prevent="submit()">
<div v-if="error" class="ui negative message"> <div v-if="error" class="ui negative message">
<div class="header">We cannot log you in</div> <div class="header"><i18next path="We cannot log you in"/></div>
<ul class="list"> <ul class="list">
<li v-if="error == 'invalid_credentials'">Please double-check your username/password couple is correct</li> <i18next tag="li" v-if="error == 'invalid_credentials'" path="Please double-check your username/password couple is correct"/>
<li v-else>An unknown error happend, this can mean the server is down or cannot be reached</li> <i18next tag="li" v-else path="An unknown error happend, this can mean the server is down or cannot be reached"/>
</ul> </ul>
</div> </div>
<div class="field"> <div class="field">
<label>Username or email</label> <i18next tag="label" path="Username or email"/>
<input <input
ref="username" ref="username"
required required
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
> >
</div> </div>
<div class="field"> <div class="field">
<label>Password</label> <i18next tag="label" path="Password"/>
<input <input
required required
type="password" type="password"
...@@ -31,9 +31,9 @@ ...@@ -31,9 +31,9 @@
v-model="credentials.password" v-model="credentials.password"
> >
</div> </div>
<button :class="['ui', {'loading': isLoading}, 'button']" type="submit">Login</button> <button :class="['ui', {'loading': isLoading}, 'button']" type="submit"><i18next path="Login"/></button>
<router-link class="ui right floated basic button" :to="{path: '/signup'}"> <router-link class="ui right floated basic button" :to="{path: '/signup'}">
Create an account <i18next path="Create an account"/>
</router-link> </router-link>
</form> </form>
</div> </div>
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
<div class="main pusher" v-title="'Log Out'"> <div class="main pusher" v-title="'Log Out'">
<div class="ui vertical stripe segment"> <div class="ui vertical stripe segment">
<div class="ui small text container"> <div class="ui small text container">
<h2>Are you sure you want to log out?</h2> <h2><i18next path="Are you sure you want to log out?"/></h2>
<p>You are currently logged in as {{ $store.state.auth.username }}</p> <i18next tag="p" path="You are currently logged in as {%0%}">{{ $store.state.auth.username }}</i18next>
<button class="ui button" @click="$store.dispatch('auth/logout')">Yes, log me out!</button> <button class="ui button" @click="$store.dispatch('auth/logout')"><i18next path="Yes, log me out!"/></button>
</form> </form>
</div> </div>
</div> </div>
......
...@@ -9,16 +9,17 @@ ...@@ -9,16 +9,17 @@
<i class="circular inverted user green icon"></i> <i class="circular inverted user green icon"></i>
<div class="content"> <div class="content">
{{ $store.state.auth.profile.username }} {{ $store.state.auth.profile.username }}
<div class="sub header">Registered since {{ signupDate }}</div> <i18next class="sub header" path="Registered since {%0%}">{{ signupDate }}</i18next>
</div> </div>
</h2> </h2>
<div class="ui basic green label">this is you!</div> <div class="ui basic green label"><i18next path="This is you!"/></div>
<div v-if="$store.state.auth.profile.is_staff" class="ui yellow label"> <div v-if="$store.state.auth.profile.is_staff" class="ui yellow label">
<i class="star icon"></i> <i class="star icon"></i>
Staff member <i18next path="Staff member"/>
</div> </div>
<router-link class="ui tiny basic button" :to="{path: '/settings'}"> <router-link class="ui tiny basic button" :to="{path: '/settings'}">
<i class="setting icon"> </i>Settings... <i class="setting icon"> </i>
<i18next path="Settings..."/>
</router-link> </router-link>
</div> </div>
......
...@@ -2,13 +2,13 @@ ...@@ -2,13 +2,13 @@
<div class="main pusher" v-title="'Account Settings'"> <div class="main pusher" v-title="'Account Settings'">
<div class="ui vertical stripe segment"> <div class="ui vertical stripe segment">
<div class="ui small text container"> <div class="ui small text container">
<h2 class="ui header">Account settings</h2> <h2 class="ui header"><i18next path="Account settings"/></h2>
<form class="ui form" @submit.prevent="submitSettings()"> <form class="ui form" @submit.prevent="submitSettings()">
<div v-if="settings.success" class="ui positive message"> <div v-if="settings.success" class="ui positive message">
<div class="header">Settings updated</div> <div class="header"><i18next path="Settings updated"/></div>
</div> </div>
<div v-if="settings.errors.length > 0" class="ui negative message"> <div v-if="settings.errors.length > 0" class="ui negative message">
<div class="header">We cannot save your settings</div> <i18next tag="div" class="header" path="We cannot save your settings"/>
<ul class="list"> <ul class="list">
<li v-for="error in settings.errors">{{ error }}</li> <li v-for="error in settings.errors">{{ error }}</li>
</ul> </ul>
...@@ -20,21 +20,21 @@ ...@@ -20,21 +20,21 @@
<option :value="c.value" v-for="c in f.choices">{{ c.label }}</option> <option :value="c.value" v-for="c in f.choices">{{ c.label }}</option>
</select> </select>
</div> </div>
<button :class="['ui', {'loading': isLoading}, 'button']" type="submit">Update settings</button> <button :class="['ui', {'loading': isLoading}, 'button']" type="submit"><i18next path="Update settings"/></button>
</form> </form>
</div> </div>
<div class="ui hidden divider"></div> <div class="ui hidden divider"></div>
<div class="ui small text container"> <div class="ui small text container">
<h2 class="ui header">Change my password</h2> <h2 class="ui header"><i18next path="Change my password"/></h2>
<form class="ui form" @submit.prevent="submitPassword()"> <form class="ui form" @submit.prevent="submitPassword()">
<div v-if="passwordError" class="ui negative message"> <div v-if="passwordError" class="ui negative message">
<div class="header">Cannot change your password</div> <div class="header"><i18next path="Cannot change your password"/></div>
<ul class="list"> <ul class="list">
<li v-if="passwordError == 'invalid_credentials'">Please double-check your password is correct</li> <i18next tag="li" v-if="passwordError == 'invalid_credentials'" path="Please double-check your password is correct"/>
</ul> </ul>
</div> </div>
<div class="field"> <div class="field">
<label>Old password</label> <label><i18next path="Old password"/></label>
<input <input
required required
type="password" type="password"
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
v-model="old_password"> v-model="old_password">
</div> </div>
<div class="field"> <div class="field">
<label>New password</label> <label><i18next path="New password"/></label>
<input <input
required required
type="password" type="password"
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
placeholder="Enter your new password" placeholder="Enter your new password"
v-model="new_password"> v-model="new_password">
</div> </div>
<button :class="['ui', {'loading': isLoading}, 'button']" type="submit">Change password</button> <button :class="['ui', {'loading': isLoading}, 'button']" type="submit"><i18next path="Change password"/></button>
</form> </form>
</div> </div>
</div> </div>
...@@ -80,16 +80,16 @@ export default { ...@@ -80,16 +80,16 @@ export default {
'privacy_level': { 'privacy_level': {
type: 'dropdown', type: 'dropdown',
initial: this.$store.state.auth.profile.privacy_level, initial: this.$store.state.auth.profile.privacy_level,
label: 'Activity visibility', label: this.$t('Activity visibility'),
help: 'Determine the visibility level of your activity', help: this.$t('Determine the visibility level of your activity'),
choices: [ choices: [
{ {
value: 'me', value: 'me',
label: 'Nobody except me' label: this.$t('Nobody except me')
}, },
{ {
value: 'instance', value: 'instance',
label: 'Everyone on this instance' label: this.$t('Everyone on this instance')
} }
] ]
} }
......
...@@ -2,19 +2,19 @@ ...@@ -2,19 +2,19 @@
<div class="main pusher" v-title="'Sign Up'"> <div class="main pusher" v-title="'Sign Up'">
<div class="ui vertical stripe segment"> <div class="ui vertical stripe segment">
<div class="ui small text container"> <div class="ui small text container">
<h2>Create a funkwhale account</h2> <h2><i18next path="Create a funkwhale account"/></h2>
<form <form
v-if="$store.state.instance.settings.users.registration_enabled.value" v-if="$store.state.instance.settings.users.registration_enabled.value"
:class="['ui', {'loading': isLoadingInstanceSetting}, 'form']" :class="['ui', {'loading': isLoadingInstanceSetting}, 'form']"
@submit.prevent="submit()"> @submit.prevent="submit()">
<div v-if="errors.length > 0" class="ui negative message"> <div v-if="errors.length > 0" class="ui negative message">
<div class="header">We cannot create your account</div> <div class="header"><i18next path="We cannot create your account"/></div>
<ul class="list"> <ul class="list">
<li v-for="error in errors">{{ error }}</li> <li v-for="error in errors">{{ error }}</li>
</ul> </ul>
</div> </div>
<div class="field"> <div class="field">
<label>Username</label> <i18next tag="label" path="Username"/>
<input <input
ref="username" ref="username"
required required
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
v-model="username"> v-model="username">
</div> </div>
<div class="field"> <div class="field">
<label>Email</label> <i18next tag="label" path="Email"/>
<input <input
ref="email" ref="email"
required required
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
v-model="email"> v-model="email">
</div> </div>
<div class="field"> <div class="field">
<label>Password</label> <i18next tag="label" path="Password"/>
<div class="ui action input"> <div class="ui action input">
<input <input
required required
...@@ -45,9 +45,9 @@ ...@@ -45,9 +45,9 @@
</span> </span>
</div> </div>
</div> </div>
<button :class="['ui', 'green', {'loading': isLoading}, 'button']" type="submit">Create my account</button> <button :class="['ui', 'green', {'loading': isLoading}, 'button']" type="submit"><i18next path="Create my account"/></button>
</form> </form>
<p v-else>Registration is currently disabled on this instance, please try again later.</p> <i18next v-else tag="p" path="Registration is currently disabled on this instance, please try again later."/>
</div> </div>
</div> </div>
</div> </div>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment