1
.gitignore
vendored
@ -72,6 +72,7 @@ dist
|
||||
|
||||
# IDE
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
# TEMORIRY
|
||||
static/uploads
|
||||
|
||||
12
README.md
@ -39,3 +39,15 @@ All reusable Components (for example avatar) should be done inside the styleguid
|
||||
``` bash
|
||||
$ yarn styleguide
|
||||
```
|
||||
|
||||
## Internationalization (i18n)
|
||||
|
||||
You can help translating the interface by joining us on [lokalise.co](https://lokalise.co/public/556252725c18dd752dd546.13222042/).
|
||||
|
||||
Thanks lokalise.co that we can use your premium account!
|
||||
|
||||
<a href="(https://lokalise.co/public/556252725c18dd752dd546.13222042/)."><img src="lokalise.png" alt="localise.co" height="32px" /></a>
|
||||
|
||||
## Attributions
|
||||
|
||||
<div>Locale Icons made by <a href="http://www.freepik.com/" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> is licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></div>
|
||||
|
||||
67
components/Dropdown.vue
Normal file
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<v-popover
|
||||
:open.sync="isPopoverOpen"
|
||||
:open-group="Math.random().toString()"
|
||||
:placement="placement"
|
||||
trigger="manual"
|
||||
:offset="offset"
|
||||
>
|
||||
<slot :toggleMenu="toggleMenu" />
|
||||
<div
|
||||
slot="popover"
|
||||
@mouseover="popoverMouseEnter"
|
||||
@mouseleave="popoveMouseLeave"
|
||||
>
|
||||
<slot
|
||||
name="popover"
|
||||
:toggleMenu="toggleMenu"
|
||||
/>
|
||||
</div>
|
||||
</v-popover>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
let mouseEnterTimer = null
|
||||
let mouseLeaveTimer = null
|
||||
|
||||
export default {
|
||||
props: {
|
||||
placement: { type: String, default: 'bottom-end' },
|
||||
offset: { type: [String, Number], default: '16' }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isPopoverOpen: false
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearTimeout(mouseEnterTimer)
|
||||
clearTimeout(mouseLeaveTimer)
|
||||
},
|
||||
methods: {
|
||||
toggleMenu() {
|
||||
this.isPopoverOpen = !this.isPopoverOpen
|
||||
},
|
||||
popoverMouseEnter() {
|
||||
clearTimeout(mouseEnterTimer)
|
||||
clearTimeout(mouseLeaveTimer)
|
||||
if (!this.isPopoverOpen) {
|
||||
mouseEnterTimer = setTimeout(() => {
|
||||
this.isPopoverOpen = true
|
||||
}, 500)
|
||||
}
|
||||
},
|
||||
popoveMouseLeave() {
|
||||
clearTimeout(mouseEnterTimer)
|
||||
clearTimeout(mouseLeaveTimer)
|
||||
if (this.isPopoverOpen) {
|
||||
mouseLeaveTimer = setTimeout(() => {
|
||||
this.isPopoverOpen = false
|
||||
}, 300)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
114
components/LocaleSwitch.vue
Normal file
@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<dropdown
|
||||
ref="menu"
|
||||
:placement="placement"
|
||||
:offset="offset"
|
||||
>
|
||||
<template
|
||||
slot="default"
|
||||
slot-scope="{toggleMenu}"
|
||||
>
|
||||
<a
|
||||
class="locale-menu"
|
||||
href="#"
|
||||
@click.prevent="toggleMenu()"
|
||||
>
|
||||
<img
|
||||
:alt="current.name"
|
||||
:title="current.name"
|
||||
:src="`/img/locale-flags/${current.code}.svg`"
|
||||
height="26"
|
||||
>
|
||||
</a>
|
||||
</template>
|
||||
<template slot="popover">
|
||||
<ul class="locale-menu-popover">
|
||||
<li
|
||||
v-for="locale in locales"
|
||||
:key="locale.code"
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
style="display: flex; align-items: center;"
|
||||
:class="[
|
||||
locale.code,
|
||||
current.code === locale.code && 'active'
|
||||
]"
|
||||
@click.prevent="changeLanguage(locale.code)"
|
||||
>
|
||||
<img
|
||||
:alt="locale.name"
|
||||
:title="locale.name"
|
||||
:src="`/img/locale-flags/${locale.code}.svg`"
|
||||
width="20"
|
||||
> {{ locale.name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
</dropdown>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Dropdown from '~/components/Dropdown'
|
||||
import find from 'lodash/find'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Dropdown
|
||||
},
|
||||
props: {
|
||||
placement: { type: String, default: 'bottom-start' },
|
||||
offset: { type: [String, Number], default: '16' }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
locales: process.env.locales
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
current() {
|
||||
return find(this.locales, { code: this.$i18n.locale() })
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeLanguage(locale) {
|
||||
this.$i18n.set(locale)
|
||||
this.$refs.menu.toggleMenu()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.locale-menu {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
ul.locale-menu-popover {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
a {
|
||||
opacity: 0.8;
|
||||
|
||||
display: block;
|
||||
padding: 0.3rem 0;
|
||||
|
||||
img {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
&.active {
|
||||
opacity: 1;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
9
components/mixins/seo.js
Normal file
@ -0,0 +1,9 @@
|
||||
export default {
|
||||
head() {
|
||||
return {
|
||||
htmlAttrs: {
|
||||
lang: this.$i18n.locale()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
24
cypress/integration/Internationalization.feature
Normal file
@ -0,0 +1,24 @@
|
||||
Feature: Internationalization
|
||||
As a user who is not very fluent in English
|
||||
I would like to see the user interface translated to my preferred language
|
||||
In order to be able to understand the interface
|
||||
|
||||
Background:
|
||||
Given I am on the "login" page
|
||||
|
||||
Scenario Outline: I select "<language>" in the language menu and see "<buttonLabel>"
|
||||
When I select "<language>" in the language menu
|
||||
Then the whole user interface appears in "<language>"
|
||||
Then I see a button with the label "<buttonLabel>"
|
||||
|
||||
Examples: Login Button
|
||||
| language | buttonLabel |
|
||||
| English | Login |
|
||||
| Deutsch | Einloggen |
|
||||
| Français | Connexion |
|
||||
| Nederlands | Inloggen |
|
||||
|
||||
Scenario: Keep preferred language after refresh
|
||||
Given I previously switched the language to "Deutsch"
|
||||
And I refresh the page
|
||||
Then the whole user interface appears in "Deutsch"
|
||||
@ -1,8 +1,30 @@
|
||||
import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'
|
||||
import find from 'lodash/find'
|
||||
import { eq } from 'semver';
|
||||
|
||||
/* global cy */
|
||||
|
||||
const baseUrl = 'http://localhost:3000'
|
||||
const username = 'Peter Lustig'
|
||||
|
||||
const locales = require('../../../locales')
|
||||
|
||||
const getLangByName = function(name) {
|
||||
return find(locales, { name })
|
||||
}
|
||||
|
||||
const openPage = function(page) {
|
||||
if (page === 'landing') {
|
||||
page = ''
|
||||
}
|
||||
cy.visit(`${baseUrl}/${page}`)
|
||||
}
|
||||
|
||||
const switchLanguage = function(name) {
|
||||
cy.get('.login-locale-switch a').click()
|
||||
cy.contains('.locale-menu-popover a', name).click()
|
||||
}
|
||||
|
||||
const login = (email, password) => {
|
||||
cy.visit(`${baseUrl}/login`)
|
||||
cy.get('input[name=email]')
|
||||
@ -38,10 +60,14 @@ Given('my user account has the role {string}', (role) => {
|
||||
// TODO: use db factories instead of seed data
|
||||
})
|
||||
|
||||
|
||||
When('I log out', logout)
|
||||
|
||||
When(`I visit the {string} page`, route => {
|
||||
cy.visit(`${baseUrl}/${route}`)
|
||||
When('I visit the {string} page', page => {
|
||||
openPage(page)
|
||||
})
|
||||
Given('I am on the {string} page', page => {
|
||||
openPage(page)
|
||||
})
|
||||
|
||||
When('I fill in my email and password combination and click submit', () => {
|
||||
@ -62,6 +88,7 @@ When('I log out through the menu in the top right corner', () => {
|
||||
|
||||
Then('I can click on my profile picture in the top right corner', () => {
|
||||
cy.get('.avatar-menu').click()
|
||||
cy.get('.avatar-menu-popover')
|
||||
})
|
||||
|
||||
Then('I can see my name {string} in the dropdown menu', () => {
|
||||
@ -70,9 +97,7 @@ Then('I can see my name {string} in the dropdown menu', () => {
|
||||
|
||||
Then('I see the login screen again', () => {
|
||||
cy.location('pathname').should('contain', '/login')
|
||||
cy.contains(
|
||||
'Wenn Du ein Konto bei Human Connection hast, melde Dich bitte hier an.'
|
||||
)
|
||||
cy.contains('If you already have a human-connection account, login here.')
|
||||
})
|
||||
|
||||
Then('I am still logged in', () => {
|
||||
@ -80,16 +105,33 @@ Then('I am still logged in', () => {
|
||||
cy.get('.avatar-menu-popover').contains(username)
|
||||
})
|
||||
|
||||
When('I navigate to the administration dashboard', () => {
|
||||
cy.get('.avatar-menu').click()
|
||||
cy.get('a').contains('Systemverwaltung').click()
|
||||
When('I select {string} in the language menu', name => {
|
||||
switchLanguage(name)
|
||||
})
|
||||
Given('I previously switched the language to {string}', name => {
|
||||
switchLanguage(name)
|
||||
})
|
||||
Then('the whole user interface appears in {string}', name => {
|
||||
const lang = getLangByName(name)
|
||||
cy.get(`html[lang=${lang.code}]`)
|
||||
cy.getCookie('locale').should('have.property', 'value', lang.code)
|
||||
})
|
||||
Then('I see a button with the label {string}', label => {
|
||||
cy.contains('button', label)
|
||||
})
|
||||
|
||||
When(`I click on {string}`, (linkOrButton) => {
|
||||
When('I navigate to the administration dashboard', () => {
|
||||
cy.get('.avatar-menu').click()
|
||||
cy.get('.avatar-menu-popover')
|
||||
.contains('Admin')
|
||||
.click()
|
||||
})
|
||||
|
||||
When('I click on {string}', linkOrButton => {
|
||||
cy.contains(linkOrButton).click()
|
||||
})
|
||||
|
||||
Then('I can see a list of categories ordered by post count:', (table) => {
|
||||
Then('I can see a list of categories ordered by post count:', table => {
|
||||
// TODO: match the table in the feature with the html table
|
||||
cy.get('thead').find('tr th').should('have.length', 3)
|
||||
const last_column = cy.get('tbody').find('tr td:last-child').then((last_column) => {
|
||||
@ -100,7 +142,7 @@ Then('I can see a list of categories ordered by post count:', (table) => {
|
||||
})
|
||||
})
|
||||
|
||||
Then('I can see a list of tags ordered by user and post count:', (table) => {
|
||||
Then('I can see a list of tags ordered by user and post count:', table => {
|
||||
// TODO: match the table in the feature with the html table
|
||||
cy.get('thead').find('tr th').should('have.length', 4)
|
||||
const last_column = cy.get('tbody').find('tr td:last-child').then((last_column) => {
|
||||
|
||||
@ -7,3 +7,11 @@
|
||||
</ds-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import seo from '~/components/mixins/seo'
|
||||
|
||||
export default {
|
||||
mixins: [seo]
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -8,55 +8,63 @@
|
||||
>
|
||||
<ds-logo />
|
||||
</a>
|
||||
<template v-if="isLoggedIn">
|
||||
<div style="float: right">
|
||||
<no-ssr>
|
||||
<v-popover
|
||||
:open.sync="isPopoverOpen"
|
||||
:open-group="Math.random().toString()"
|
||||
placement="bottom-end"
|
||||
trigger="manual"
|
||||
offset="10"
|
||||
style="float: right"
|
||||
>
|
||||
<a
|
||||
class="avatar-menu"
|
||||
:href="$router.resolve({name: 'profile-slug', params: {slug: user.slug}}).href"
|
||||
@click.prevent="toggleMenu()"
|
||||
>
|
||||
<ds-avatar
|
||||
:image="user.avatar"
|
||||
:name="user.name"
|
||||
size="42"
|
||||
/>
|
||||
</a>
|
||||
<div
|
||||
slot="popover"
|
||||
class="avatar-menu-popover"
|
||||
style="padding-top: .5rem; padding-bottom: .5rem;"
|
||||
@mouseover="popoverMouseEnter"
|
||||
@mouseleave="popoveMouseLeave">
|
||||
Hallo <b>{{ user.name }}</b>
|
||||
<ds-menu
|
||||
:routes="routes"
|
||||
:is-exact="isExact"
|
||||
style="margin-left: -15px; margin-right: -15px; padding-top: 1rem; padding-bottom: 1rem;">
|
||||
<ds-menu-item
|
||||
slot="Navigation"
|
||||
slot-scope="item"
|
||||
:route="item.route"
|
||||
:parents="item.parents"
|
||||
@click.native="toggleMenu">
|
||||
<ds-icon :name="item.route.icon" /> {{ item.route.name }}
|
||||
</ds-menu-item>
|
||||
</ds-menu>
|
||||
<ds-space margin="xx-small" />
|
||||
<nuxt-link :to="{ name: 'logout'}">
|
||||
<ds-icon name="sign-out" /> Logout
|
||||
</nuxt-link>
|
||||
</div>
|
||||
</v-popover>
|
||||
<locale-switch
|
||||
class="topbar-locale-switch"
|
||||
placement="bottom"
|
||||
offset="24"
|
||||
/>
|
||||
</no-ssr>
|
||||
</template>
|
||||
<template v-if="isLoggedIn">
|
||||
<no-ssr>
|
||||
<dropdown class="avatar-menu">
|
||||
<template
|
||||
slot="default"
|
||||
slot-scope="{toggleMenu}"
|
||||
>
|
||||
<a
|
||||
class="avatar-menu-trigger"
|
||||
:href="$router.resolve({name: 'profile-slug', params: {slug: user.slug}}).href"
|
||||
@click.prevent="toggleMenu()"
|
||||
>
|
||||
<ds-avatar
|
||||
:image="user.avatar"
|
||||
:name="user.name"
|
||||
size="42"
|
||||
/>
|
||||
</a>
|
||||
</template>
|
||||
<template
|
||||
slot="popover"
|
||||
slot-scope="{toggleMenu}"
|
||||
>
|
||||
<div class="avatar-menu-popover">
|
||||
{{ $t('login.hello') }} <b>{{ user.name }}</b>
|
||||
<ds-menu
|
||||
:routes="routes"
|
||||
:is-exact="isExact"
|
||||
>
|
||||
<ds-menu-item
|
||||
slot="Navigation"
|
||||
slot-scope="item"
|
||||
:route="item.route"
|
||||
:parents="item.parents"
|
||||
@click.native="toggleMenu"
|
||||
>
|
||||
<ds-icon :name="item.route.icon" /> {{ item.route.name }}
|
||||
</ds-menu-item>
|
||||
</ds-menu>
|
||||
<ds-space margin="xx-small" />
|
||||
<nuxt-link :to="{ name: 'logout'}">
|
||||
<ds-icon name="sign-out" /> {{ $t('login.logout') }}
|
||||
</nuxt-link>
|
||||
</div>
|
||||
</template>
|
||||
</dropdown>
|
||||
</no-ssr>
|
||||
</template>
|
||||
</div>
|
||||
</ds-container>
|
||||
</div>
|
||||
<ds-container>
|
||||
@ -69,16 +77,16 @@
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { setTimeout } from 'timers'
|
||||
let mouseEnterTimer = null
|
||||
let mouseLeaveTimer = null
|
||||
import LocaleSwitch from '~/components/LocaleSwitch'
|
||||
import Dropdown from '~/components/Dropdown'
|
||||
import seo from '~/components/mixins/seo'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
isPopoverOpen: false
|
||||
}
|
||||
components: {
|
||||
Dropdown,
|
||||
LocaleSwitch
|
||||
},
|
||||
mixins: [seo],
|
||||
computed: {
|
||||
...mapGetters({
|
||||
user: 'auth/user',
|
||||
@ -91,19 +99,19 @@ export default {
|
||||
}
|
||||
let routes = [
|
||||
{
|
||||
name: 'Mein Profil',
|
||||
name: this.$t('profile.name'),
|
||||
path: `/profile/${this.user.slug}`,
|
||||
icon: 'user'
|
||||
},
|
||||
{
|
||||
name: 'Einstellungen',
|
||||
name: this.$t('settings.name'),
|
||||
path: `/settings`,
|
||||
icon: 'cogs'
|
||||
}
|
||||
]
|
||||
if (this.isAdmin) {
|
||||
routes.push({
|
||||
name: 'Systemverwaltung',
|
||||
name: this.$t('admin.name'),
|
||||
path: `/admin`,
|
||||
icon: 'shield'
|
||||
})
|
||||
@ -111,35 +119,38 @@ export default {
|
||||
return routes
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearTimeout(mouseEnterTimer)
|
||||
clearTimeout(mouseLeaveTimer)
|
||||
},
|
||||
methods: {
|
||||
toggleMenu() {
|
||||
this.isPopoverOpen = !this.isPopoverOpen
|
||||
},
|
||||
isExact(url) {
|
||||
return this.$route.path.indexOf(url) === 0
|
||||
},
|
||||
popoverMouseEnter() {
|
||||
clearTimeout(mouseEnterTimer)
|
||||
clearTimeout(mouseLeaveTimer)
|
||||
if (!this.isPopoverOpen) {
|
||||
mouseEnterTimer = setTimeout(() => {
|
||||
this.isPopoverOpen = true
|
||||
}, 500)
|
||||
}
|
||||
},
|
||||
popoveMouseLeave() {
|
||||
clearTimeout(mouseEnterTimer)
|
||||
clearTimeout(mouseLeaveTimer)
|
||||
if (this.isPopoverOpen) {
|
||||
mouseLeaveTimer = setTimeout(() => {
|
||||
this.isPopoverOpen = false
|
||||
}, 300)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.topbar-locale-switch {
|
||||
display: inline-block;
|
||||
top: 8px;
|
||||
right: 10px;
|
||||
position: relative;
|
||||
}
|
||||
.avatar-menu {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.avatar-menu-trigger {
|
||||
user-select: none;
|
||||
}
|
||||
.avatar-menu-popover {
|
||||
display: inline-block;
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
|
||||
nav {
|
||||
margin-left: -15px;
|
||||
margin-right: -15px;
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
97
locales/de.json
Normal file
@ -0,0 +1,97 @@
|
||||
{
|
||||
"login": {
|
||||
"copy": "Wenn Du ein Konto bei Human Connection hast, melde Dich bitte hier an.",
|
||||
"login": "Einloggen",
|
||||
"logout": "Ausloggen",
|
||||
"email": "Deine E-Mail",
|
||||
"password": "Dein Passwort",
|
||||
"moreInfo": "Was ist Human Connection?",
|
||||
"hello": "Hallo"
|
||||
},
|
||||
"profile": {
|
||||
"name": "Mein Profil",
|
||||
"memberSince": "Mitglied seit",
|
||||
"follow": "Folgen",
|
||||
"followers": "Folgen",
|
||||
"following": "Folgt"
|
||||
},
|
||||
"settings": {
|
||||
"name": "Einstellungen",
|
||||
"data": {
|
||||
"name": "Deine Daten"
|
||||
},
|
||||
"security": {
|
||||
"name": "Sicherheit"
|
||||
},
|
||||
"invites": {
|
||||
"name": "Einladungen"
|
||||
},
|
||||
"download": {
|
||||
"name": "Daten herunterladen"
|
||||
},
|
||||
"delete": {
|
||||
"name": "Konto löschen"
|
||||
},
|
||||
"organizations": {
|
||||
"name": "Meine Organisationen"
|
||||
},
|
||||
"languages": {
|
||||
"name": "Sprachen"
|
||||
}
|
||||
},
|
||||
"admin": {
|
||||
"name": "Systemverwaltung",
|
||||
"dashboard": {
|
||||
"name": "Startzentrale",
|
||||
"users": "Benutzer",
|
||||
"posts": "Beiträge",
|
||||
"comments": "Kommentare",
|
||||
"notifications": "Benachrichtigungen",
|
||||
"organizations": "Organisationen",
|
||||
"projects": "Projekte",
|
||||
"invites": "Einladungen",
|
||||
"follows": "Folgen",
|
||||
"shouts": "Shouts"
|
||||
},
|
||||
"organizations": {
|
||||
"name": "Organisationen"
|
||||
},
|
||||
"users": {
|
||||
"name": "Benutzer"
|
||||
},
|
||||
"pages": {
|
||||
"name": "Seiten"
|
||||
},
|
||||
"notifications": {
|
||||
"name": "Benachrichtigungen"
|
||||
},
|
||||
"categories": {
|
||||
"name": "Kategorien",
|
||||
"categoryName": "Name",
|
||||
"postCount": "Beiträge"
|
||||
},
|
||||
"tags": {
|
||||
"name": "Schlagworte",
|
||||
"tagCountUnique": "Benutzer",
|
||||
"tagCount": "Beiträge"
|
||||
},
|
||||
"settings": {
|
||||
"name": "Einstellungen"
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"name": "Beitrag",
|
||||
"moreInfo": {
|
||||
"name": "Mehr Info"
|
||||
},
|
||||
"takeAction": {
|
||||
"name": "Aktiv werden"
|
||||
}
|
||||
},
|
||||
"quotes": {
|
||||
"african": {
|
||||
"quote": "Viele kleine Leute, an vielen kleinen Orten, die viele kleine Dinge tun, werden das Antlitz dieser Welt verändern.",
|
||||
"author": "Afrikanisches Sprichwort"
|
||||
}
|
||||
}
|
||||
}
|
||||
97
locales/en.json
Normal file
@ -0,0 +1,97 @@
|
||||
{
|
||||
"login": {
|
||||
"copy": "If you already have a human-connection account, login here.",
|
||||
"login": "Login",
|
||||
"logout": "Logout",
|
||||
"email": "Your Email",
|
||||
"password": "Your Password",
|
||||
"moreInfo": "What is Human Connection?",
|
||||
"hello": "Hello"
|
||||
},
|
||||
"profile": {
|
||||
"name": "My Profile",
|
||||
"memberSince": "Member since",
|
||||
"follow": "Follow",
|
||||
"followers": "Followers",
|
||||
"following": "Following"
|
||||
},
|
||||
"settings": {
|
||||
"name": "Settings",
|
||||
"data": {
|
||||
"name": "Your data"
|
||||
},
|
||||
"security": {
|
||||
"name": "Security"
|
||||
},
|
||||
"invites": {
|
||||
"name": "Invites"
|
||||
},
|
||||
"download": {
|
||||
"name": "Download Data"
|
||||
},
|
||||
"delete": {
|
||||
"name": "Delete Account"
|
||||
},
|
||||
"organizations": {
|
||||
"name": "My Organizations"
|
||||
},
|
||||
"languages": {
|
||||
"name": "Languages"
|
||||
}
|
||||
},
|
||||
"admin": {
|
||||
"name": "Admin",
|
||||
"dashboard": {
|
||||
"name": "Dashboard",
|
||||
"users": "Users",
|
||||
"posts": "Posts",
|
||||
"comments": "Comments",
|
||||
"notifications": "Notifications",
|
||||
"organizations": "Organizations",
|
||||
"projects": "Projects",
|
||||
"invites": "Invites",
|
||||
"follows": "Follows",
|
||||
"shouts": "Shouts"
|
||||
},
|
||||
"organizations": {
|
||||
"name": "Organizations"
|
||||
},
|
||||
"users": {
|
||||
"name": "Users"
|
||||
},
|
||||
"pages": {
|
||||
"name": "Pages"
|
||||
},
|
||||
"notifications": {
|
||||
"name": "Notifications"
|
||||
},
|
||||
"categories": {
|
||||
"name": "Categories",
|
||||
"categoryName": "Name",
|
||||
"postCount": "Posts"
|
||||
},
|
||||
"tags": {
|
||||
"name": "Tags",
|
||||
"tagCountUnique": "Users",
|
||||
"tagCount": "Posts"
|
||||
},
|
||||
"settings": {
|
||||
"name": "Settings"
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"name": "Post",
|
||||
"moreInfo": {
|
||||
"name": "More info"
|
||||
},
|
||||
"takeAction": {
|
||||
"name": "Take action"
|
||||
}
|
||||
},
|
||||
"quotes": {
|
||||
"african": {
|
||||
"quote": "Many small people in many small places do many small things, that can alter the face of the world.",
|
||||
"author": "African proverb"
|
||||
}
|
||||
}
|
||||
}
|
||||
79
locales/es.json
Normal file
@ -0,0 +1,79 @@
|
||||
{
|
||||
"login": {
|
||||
"copy": "Si ya tiene una cuenta de Human Connection, inicie sesión aquí.",
|
||||
"logout": "Cierre de sesión",
|
||||
"email": "Tu correo electrónico",
|
||||
"password": "Tu contraseña",
|
||||
"moreInfo": "¿Qué es Human Connection?",
|
||||
"hello": "Hola"
|
||||
},
|
||||
"profile": {
|
||||
"name": "Mi perfil",
|
||||
"memberSince": "Miembro desde",
|
||||
"followers": "Seguidores"
|
||||
},
|
||||
"settings": {
|
||||
"data": {
|
||||
"name": "Sus datos"
|
||||
},
|
||||
"security": {
|
||||
"name": "Seguridad"
|
||||
},
|
||||
"invites": {
|
||||
"name": "Invita"
|
||||
},
|
||||
"download": {
|
||||
"name": "Descargar datos"
|
||||
},
|
||||
"organizations": {
|
||||
"name": "Mis organizaciones"
|
||||
},
|
||||
"languages": {
|
||||
"name": "Idiomas"
|
||||
}
|
||||
},
|
||||
"admin": {
|
||||
"name": "Admin",
|
||||
"dashboard": {
|
||||
"users": "Usuarios",
|
||||
"comments": "Comentarios",
|
||||
"organizations": "Organizaciones",
|
||||
"projects": "Proyectos",
|
||||
"invites": "Invita",
|
||||
"follows": "Sigue"
|
||||
},
|
||||
"organizations": {
|
||||
"name": "Organizaciones"
|
||||
},
|
||||
"users": {
|
||||
"name": "Usuarios"
|
||||
},
|
||||
"pages": {
|
||||
"name": "Páginas"
|
||||
},
|
||||
"notifications": {
|
||||
"name": "Notificaciones"
|
||||
},
|
||||
"categories": {
|
||||
"name": "Categorías",
|
||||
"categoryName": "Nombre"
|
||||
},
|
||||
"tags": {
|
||||
"name": "Etiquetas",
|
||||
"tagCountUnique": "Usuarios"
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"moreInfo": {
|
||||
"name": "Más info"
|
||||
},
|
||||
"takeAction": {
|
||||
"name": "Tomar acción"
|
||||
}
|
||||
},
|
||||
"quotes": {
|
||||
"african": {
|
||||
"author": "Proverbio africano"
|
||||
}
|
||||
}
|
||||
}
|
||||
97
locales/fr.json
Normal file
@ -0,0 +1,97 @@
|
||||
{
|
||||
"login": {
|
||||
"copy": "Si vous avez déjà un compte human-connection, connectez-vous ici.",
|
||||
"login": "Connexion",
|
||||
"logout": "Déconnexion",
|
||||
"email": "Votre Message électronique",
|
||||
"password": "Votre mot de passe",
|
||||
"moreInfo": "Qu'est-ce que Human Connection?",
|
||||
"hello": "Bonjour"
|
||||
},
|
||||
"profile": {
|
||||
"name": "Mon profil",
|
||||
"memberSince": "Membre depuis",
|
||||
"follow": "Suivre",
|
||||
"followers": "Suiveurs",
|
||||
"following": "Suivant"
|
||||
},
|
||||
"settings": {
|
||||
"name": "Paramètres",
|
||||
"data": {
|
||||
"name": "Vos données"
|
||||
},
|
||||
"security": {
|
||||
"name": "Sécurité"
|
||||
},
|
||||
"invites": {
|
||||
"name": "Invite"
|
||||
},
|
||||
"download": {
|
||||
"name": "Télécharger les données"
|
||||
},
|
||||
"delete": {
|
||||
"name": "Supprimer un compte"
|
||||
},
|
||||
"organizations": {
|
||||
"name": "Mes organisations"
|
||||
},
|
||||
"languages": {
|
||||
"name": "Langues"
|
||||
}
|
||||
},
|
||||
"admin": {
|
||||
"name": "Admin",
|
||||
"dashboard": {
|
||||
"name": "Tableau de bord",
|
||||
"users": "Utilisateurs",
|
||||
"posts": "Postes",
|
||||
"comments": "Commentaires",
|
||||
"notifications": "Notifications",
|
||||
"organizations": "Organisations",
|
||||
"projects": "Projets",
|
||||
"invites": "Invite",
|
||||
"follows": "Suit",
|
||||
"shouts": "Cris"
|
||||
},
|
||||
"organizations": {
|
||||
"name": "Organisations"
|
||||
},
|
||||
"users": {
|
||||
"name": "Utilisateurs"
|
||||
},
|
||||
"pages": {
|
||||
"name": "Pages"
|
||||
},
|
||||
"notifications": {
|
||||
"name": "Notifications"
|
||||
},
|
||||
"categories": {
|
||||
"name": "Catégories",
|
||||
"categoryName": "Nom",
|
||||
"postCount": "Postes"
|
||||
},
|
||||
"tags": {
|
||||
"name": "Étiquettes",
|
||||
"tagCountUnique": "Utilisateurs",
|
||||
"tagCount": "Postes"
|
||||
},
|
||||
"settings": {
|
||||
"name": "Paramètres"
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"name": "Post",
|
||||
"moreInfo": {
|
||||
"name": "Plus d'infos"
|
||||
},
|
||||
"takeAction": {
|
||||
"name": "Passez à l'action"
|
||||
}
|
||||
},
|
||||
"quotes": {
|
||||
"african": {
|
||||
"quote": "Beaucoup de petites personnes dans beaucoup de petits endroits font beaucoup de petites choses, qui peuvent changer la face du monde.",
|
||||
"author": "Proverbe africain"
|
||||
}
|
||||
}
|
||||
}
|
||||
50
locales/index.js
Normal file
@ -0,0 +1,50 @@
|
||||
module.exports = [
|
||||
{
|
||||
name: 'English',
|
||||
code: 'en',
|
||||
iso: 'en-US',
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
name: 'Deutsch',
|
||||
code: 'de',
|
||||
iso: 'de-DE',
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
name: 'Nederlands',
|
||||
code: 'nl',
|
||||
iso: 'nl-NL',
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
name: 'Français',
|
||||
code: 'fr',
|
||||
iso: 'fr-FR',
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
name: 'Italiano',
|
||||
code: 'it',
|
||||
iso: 'it-IT',
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
name: 'Español',
|
||||
code: 'es',
|
||||
iso: 'es-ES',
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
name: 'Portuguese',
|
||||
code: 'pt',
|
||||
iso: 'pt-PT',
|
||||
enabled: true
|
||||
},
|
||||
{
|
||||
name: 'Polski',
|
||||
code: 'pl',
|
||||
iso: 'pl-PL',
|
||||
enabled: true
|
||||
}
|
||||
]
|
||||
89
locales/it.json
Normal file
@ -0,0 +1,89 @@
|
||||
{
|
||||
"login": {
|
||||
"copy": "Se hai già un account di Human Connection, accedi qui.",
|
||||
"logout": "Logout",
|
||||
"email": "La tua email",
|
||||
"password": "La tua password",
|
||||
"moreInfo": "Che cosa è Human Connection?",
|
||||
"hello": "Ciao"
|
||||
},
|
||||
"profile": {
|
||||
"name": "Il mio profilo",
|
||||
"follow": "Seguire",
|
||||
"followers": "Seguaci"
|
||||
},
|
||||
"settings": {
|
||||
"name": "Impostazioni",
|
||||
"data": {
|
||||
"name": "I tuoi dati"
|
||||
},
|
||||
"security": {
|
||||
"name": "Sicurezza"
|
||||
},
|
||||
"invites": {
|
||||
"name": "Inviti"
|
||||
},
|
||||
"download": {
|
||||
"name": "Scaricare i dati"
|
||||
},
|
||||
"delete": {
|
||||
"name": "Elimina Account"
|
||||
},
|
||||
"organizations": {
|
||||
"name": "Mie organizzazioni"
|
||||
},
|
||||
"languages": {
|
||||
"name": "Lingue"
|
||||
}
|
||||
},
|
||||
"admin": {
|
||||
"name": "Admin",
|
||||
"dashboard": {
|
||||
"name": "Cruscotto",
|
||||
"users": "Utenti",
|
||||
"comments": "Commenti",
|
||||
"notifications": "Notifiche",
|
||||
"organizations": "Organizzazioni",
|
||||
"projects": "Progetti",
|
||||
"invites": "Inviti",
|
||||
"follows": "Segue"
|
||||
},
|
||||
"organizations": {
|
||||
"name": "Organizzazioni"
|
||||
},
|
||||
"users": {
|
||||
"name": "Utenti"
|
||||
},
|
||||
"pages": {
|
||||
"name": "Pagine"
|
||||
},
|
||||
"notifications": {
|
||||
"name": "Notifiche"
|
||||
},
|
||||
"categories": {
|
||||
"name": "Categorie",
|
||||
"categoryName": "Nome"
|
||||
},
|
||||
"tags": {
|
||||
"name": "Tag",
|
||||
"tagCountUnique": "Utenti",
|
||||
"tagCount": "Messaggi"
|
||||
},
|
||||
"settings": {
|
||||
"name": "Impostazioni"
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"moreInfo": {
|
||||
"name": "Ulteriori informazioni"
|
||||
},
|
||||
"takeAction": {
|
||||
"name": "Agire"
|
||||
}
|
||||
},
|
||||
"quotes": {
|
||||
"african": {
|
||||
"author": "Proverbio africano"
|
||||
}
|
||||
}
|
||||
}
|
||||
90
locales/nl.json
Normal file
@ -0,0 +1,90 @@
|
||||
{
|
||||
"login": {
|
||||
"copy": "Als u al een mini-aansluiting account heeft, log dan hier in.",
|
||||
"login": "Inloggen",
|
||||
"logout": "Uitloggen",
|
||||
"email": "Uw E-mail",
|
||||
"password": "Uw Wachtwoord",
|
||||
"moreInfo": "Wat is Human Connection?",
|
||||
"hello": "Hallo"
|
||||
},
|
||||
"profile": {
|
||||
"name": "Mijn profiel",
|
||||
"memberSince": "Lid sinds",
|
||||
"follow": "Volgen",
|
||||
"followers": "Volgelingen",
|
||||
"following": "Volgt"
|
||||
},
|
||||
"settings": {
|
||||
"name": "Instellingen",
|
||||
"data": {
|
||||
"name": "Uw gegevens"
|
||||
},
|
||||
"security": {
|
||||
"name": "Veiligheid"
|
||||
},
|
||||
"download": {
|
||||
"name": "Gegevens downloaden"
|
||||
},
|
||||
"delete": {
|
||||
"name": "Account verwijderen"
|
||||
},
|
||||
"organizations": {
|
||||
"name": "Mijn Organisaties"
|
||||
},
|
||||
"languages": {
|
||||
"name": "Talen"
|
||||
}
|
||||
},
|
||||
"admin": {
|
||||
"name": "Admin",
|
||||
"dashboard": {
|
||||
"name": "Dashboard",
|
||||
"users": "Gebruikers",
|
||||
"posts": "Berichten",
|
||||
"comments": "Opmerkingen",
|
||||
"notifications": "Meldingen",
|
||||
"organizations": "Organisaties",
|
||||
"projects": "Projecten",
|
||||
"follows": "Volgt",
|
||||
"shouts": "Shouts"
|
||||
},
|
||||
"organizations": {
|
||||
"name": "Organisaties"
|
||||
},
|
||||
"users": {
|
||||
"name": "Gebruikers"
|
||||
},
|
||||
"notifications": {
|
||||
"name": "Meldingen"
|
||||
},
|
||||
"categories": {
|
||||
"name": "Categorieën",
|
||||
"categoryName": "Naam",
|
||||
"postCount": "Berichten"
|
||||
},
|
||||
"tags": {
|
||||
"name": "Tags",
|
||||
"tagCountUnique": "Gebruikers",
|
||||
"tagCount": "Berichten"
|
||||
},
|
||||
"settings": {
|
||||
"name": "Instellingen"
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"name": "Post",
|
||||
"moreInfo": {
|
||||
"name": "Meer info"
|
||||
},
|
||||
"takeAction": {
|
||||
"name": "Onderneem actie"
|
||||
}
|
||||
},
|
||||
"quotes": {
|
||||
"african": {
|
||||
"quote": "Veel kleine mensen op veel kleine plaatsen doen veel kleine dingen, die het gezicht van de wereld kunnen veranderen.",
|
||||
"author": "Afrikaans spreekwoord"
|
||||
}
|
||||
}
|
||||
}
|
||||
97
locales/pl.json
Normal file
@ -0,0 +1,97 @@
|
||||
{
|
||||
"login": {
|
||||
"copy": "Jeśli masz już konto Human Connection, zaloguj się tutaj.",
|
||||
"login": "Login",
|
||||
"logout": "Wyloguj się",
|
||||
"email": "Twój adres e-mail",
|
||||
"password": "Twoje hasło",
|
||||
"moreInfo": "Co to jest Human Connection?",
|
||||
"hello": "Cześć"
|
||||
},
|
||||
"profile": {
|
||||
"name": "Mój profil",
|
||||
"memberSince": "Członek od",
|
||||
"follow": "Obserwuj",
|
||||
"followers": "Obserwujący",
|
||||
"following": "Obserwowani"
|
||||
},
|
||||
"settings": {
|
||||
"name": "Ustawienia",
|
||||
"data": {
|
||||
"name": "Twoje dane"
|
||||
},
|
||||
"security": {
|
||||
"name": "Bezpieczeństwo"
|
||||
},
|
||||
"invites": {
|
||||
"name": "Zaproszenia"
|
||||
},
|
||||
"download": {
|
||||
"name": "Pobierz dane"
|
||||
},
|
||||
"delete": {
|
||||
"name": "Usuń konto"
|
||||
},
|
||||
"organizations": {
|
||||
"name": "Moje organizacje"
|
||||
},
|
||||
"languages": {
|
||||
"name": "Języki"
|
||||
}
|
||||
},
|
||||
"admin": {
|
||||
"name": "Admin",
|
||||
"dashboard": {
|
||||
"name": "Tablica rozdzielcza",
|
||||
"users": "Użytkownicy",
|
||||
"posts": "Posty",
|
||||
"comments": "Komentarze",
|
||||
"notifications": "Powiadomienia",
|
||||
"organizations": "Organizacje",
|
||||
"projects": "Projekty",
|
||||
"invites": "Zaproszenia",
|
||||
"follows": "Obserwowań",
|
||||
"shouts": "Wykrzyki"
|
||||
},
|
||||
"organizations": {
|
||||
"name": "Organizacje"
|
||||
},
|
||||
"users": {
|
||||
"name": "Użytkownicy"
|
||||
},
|
||||
"pages": {
|
||||
"name": "Strony"
|
||||
},
|
||||
"notifications": {
|
||||
"name": "Powiadomienia"
|
||||
},
|
||||
"categories": {
|
||||
"name": "Kategorie",
|
||||
"categoryName": "Nazwa",
|
||||
"postCount": "Posty"
|
||||
},
|
||||
"tags": {
|
||||
"name": "Tagi",
|
||||
"tagCountUnique": "Użytkownicy",
|
||||
"tagCount": "Posty"
|
||||
},
|
||||
"settings": {
|
||||
"name": "Ustawienia"
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"name": "Post",
|
||||
"moreInfo": {
|
||||
"name": "Więcej informacji"
|
||||
},
|
||||
"takeAction": {
|
||||
"name": "Podejmij działanie"
|
||||
}
|
||||
},
|
||||
"quotes": {
|
||||
"african": {
|
||||
"quote": "Wielu małych ludzi w wielu małych miejscach robi wiele małych rzeczy, które mogą zmienić oblicze świata.",
|
||||
"author": "Afrykańskie przysłowie"
|
||||
}
|
||||
}
|
||||
}
|
||||
96
locales/pt.json
Normal file
@ -0,0 +1,96 @@
|
||||
{
|
||||
"login": {
|
||||
"copy": "Se você já tem uma conta no Human Connection, faça o login aqui.",
|
||||
"login": "Login",
|
||||
"logout": "Sair",
|
||||
"email": "Seu email",
|
||||
"password": "Sua senha",
|
||||
"moreInfo": "O que é o Human Connection?",
|
||||
"hello": "Olá"
|
||||
},
|
||||
"profile": {
|
||||
"name": "Meu perfil",
|
||||
"memberSince": "Membro desde",
|
||||
"follow": "Seguir",
|
||||
"followers": "Seguidores",
|
||||
"following": "Seguindo"
|
||||
},
|
||||
"settings": {
|
||||
"name": "Configurações",
|
||||
"data": {
|
||||
"name": "Seus Dados"
|
||||
},
|
||||
"security": {
|
||||
"name": "Segurança"
|
||||
},
|
||||
"invites": {
|
||||
"name": "Convites"
|
||||
},
|
||||
"download": {
|
||||
"name": "Baixar dados"
|
||||
},
|
||||
"delete": {
|
||||
"name": "Deletar conta"
|
||||
},
|
||||
"organizations": {
|
||||
"name": "Minhas Organizações"
|
||||
},
|
||||
"languages": {
|
||||
"name": "Linguagens"
|
||||
}
|
||||
},
|
||||
"admin": {
|
||||
"name": "Administrator",
|
||||
"dashboard": {
|
||||
"name": "Painel de controle",
|
||||
"users": "Usuários",
|
||||
"posts": "Postagens",
|
||||
"comments": "Comentários",
|
||||
"notifications": "Notificações",
|
||||
"organizations": "Organizações",
|
||||
"projects": "Projetos",
|
||||
"invites": "Convites",
|
||||
"follows": "Seguidores"
|
||||
},
|
||||
"organizations": {
|
||||
"name": "Organizações"
|
||||
},
|
||||
"users": {
|
||||
"name": "Usuários"
|
||||
},
|
||||
"pages": {
|
||||
"name": "Páginas"
|
||||
},
|
||||
"notifications": {
|
||||
"name": "Notificações"
|
||||
},
|
||||
"categories": {
|
||||
"name": "Categorias",
|
||||
"categoryName": "Nome",
|
||||
"postCount": "Postagens"
|
||||
},
|
||||
"tags": {
|
||||
"name": "Etiquetas",
|
||||
"tagCountUnique": "Usuários",
|
||||
"tagCount": "Postagens"
|
||||
},
|
||||
"settings": {
|
||||
"name": "Configurações"
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"name": "Postar",
|
||||
"moreInfo": {
|
||||
"name": "Mais informações"
|
||||
},
|
||||
"takeAction": {
|
||||
"name": "Tomar uma ação"
|
||||
}
|
||||
},
|
||||
"quotes": {
|
||||
"african": {
|
||||
"quote": "Pequenos grupos de pessoas, em pequenos locais podem fazer várias coisas pequenas, mas que podem alterar o mundo ao nosso redor.",
|
||||
"author": "Provérbio Africano"
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
lokalise.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
@ -1,4 +1,4 @@
|
||||
import { isEmpty } from 'lodash'
|
||||
import isEmpty from 'lodash/isEmpty'
|
||||
|
||||
export default async ({ store, env, route, redirect }) => {
|
||||
let publicPages = env.publicPages
|
||||
|
||||
@ -26,7 +26,9 @@ module.exports = {
|
||||
'pages-slug'
|
||||
],
|
||||
// pages to keep alive
|
||||
keepAlivePages: ['index']
|
||||
keepAlivePages: ['index'],
|
||||
// active locales
|
||||
locales: require('./locales')
|
||||
},
|
||||
/*
|
||||
** Headers of the page
|
||||
@ -59,6 +61,7 @@ module.exports = {
|
||||
** Plugins to load before mounting the App
|
||||
*/
|
||||
plugins: [
|
||||
{ src: '~/plugins/i18n.js', ssr: true },
|
||||
{ src: '~/plugins/keep-alive.js', ssr: false },
|
||||
{ src: '~/plugins/design-system.js', ssr: true },
|
||||
{ src: '~/plugins/vue-directives.js', ssr: false },
|
||||
@ -71,30 +74,6 @@ module.exports = {
|
||||
middleware: ['authenticated'],
|
||||
linkActiveClass: 'router-active-link'
|
||||
},
|
||||
/* router: {
|
||||
routes: [
|
||||
{
|
||||
name: 'index',
|
||||
path: '/',
|
||||
component: 'pages/index.vue'
|
||||
},
|
||||
{
|
||||
name: 'post-slug',
|
||||
path: '/post/:slug',
|
||||
component: 'pages/post/_slug.vue',
|
||||
children: [
|
||||
{
|
||||
path: 'more-info',
|
||||
component: 'pages/post/_slug.vue'
|
||||
},
|
||||
{
|
||||
path: 'take-action',
|
||||
component: 'pages/post/_slug.vue'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}, */
|
||||
|
||||
/*
|
||||
** Nuxt.js modules
|
||||
@ -102,6 +81,7 @@ module.exports = {
|
||||
modules: [
|
||||
['@nuxtjs/dotenv', { only: envWhitelist }],
|
||||
['nuxt-env', { keys: envWhitelist }],
|
||||
'cookie-universal-nuxt',
|
||||
'@nuxtjs/apollo',
|
||||
'@nuxtjs/axios',
|
||||
[
|
||||
@ -172,6 +152,7 @@ module.exports = {
|
||||
*/
|
||||
build: {
|
||||
/*
|
||||
* TODO: import the polyfill instead of using the deprecated vendor key
|
||||
* Polyfill missing ES6 & 7 Methods to work on older Browser
|
||||
*/
|
||||
vendor: ['@babel/polyfill'],
|
||||
|
||||
@ -42,6 +42,7 @@
|
||||
"@nuxtjs/axios": "^5.3.6",
|
||||
"@nuxtjs/dotenv": "^1.3.0",
|
||||
"accounting": "^0.4.1",
|
||||
"cookie-universal-nuxt": "^2.0.11",
|
||||
"cross-env": "^5.2.0",
|
||||
"date-fns": "^2.0.0-alpha.26",
|
||||
"express": "^4.16.3",
|
||||
@ -52,7 +53,8 @@
|
||||
"nuxt-env": "^0.0.4",
|
||||
"v-tooltip": "^2.0.0-rc.33",
|
||||
"vue-count-to": "^1.0.13",
|
||||
"vue-izitoast": "1.1.2"
|
||||
"vue-izitoast": "1.1.2",
|
||||
"vuex-i18n": "^1.10.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/eslint-config-prettier": "^4.0.1",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<ds-heading tag="h1">
|
||||
Administartion
|
||||
{{ $t('admin.name') }}
|
||||
</ds-heading>
|
||||
<ds-flex gutter="small">
|
||||
<ds-flex-item :width="{ base: '200px' }">
|
||||
@ -21,39 +21,39 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
routes: [
|
||||
computed: {
|
||||
routes() {
|
||||
return [
|
||||
{
|
||||
name: 'Dashboard',
|
||||
name: this.$t('admin.dashboard.name'),
|
||||
path: `/admin`
|
||||
},
|
||||
{
|
||||
name: 'Users',
|
||||
name: this.$t('admin.users.name'),
|
||||
path: `/admin/users`
|
||||
},
|
||||
{
|
||||
name: 'Organizations',
|
||||
name: this.$t('admin.organizations.name'),
|
||||
path: `/admin/organizations`
|
||||
},
|
||||
{
|
||||
name: 'Pages',
|
||||
name: this.$t('admin.pages.name'),
|
||||
path: `/admin/pages`
|
||||
},
|
||||
{
|
||||
name: 'Notifications',
|
||||
name: this.$t('admin.notifications.name'),
|
||||
path: `/admin/notifications`
|
||||
},
|
||||
{
|
||||
name: 'Categories',
|
||||
name: this.$t('admin.categories.name'),
|
||||
path: `/admin/categories`
|
||||
},
|
||||
{
|
||||
name: 'Tags',
|
||||
name: this.$t('admin.tags.name'),
|
||||
path: `/admin/tags`
|
||||
},
|
||||
{
|
||||
name: 'Settings',
|
||||
name: this.$t('admin.settings.name'),
|
||||
path: `/admin/settings`
|
||||
}
|
||||
]
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<ds-card space="small">
|
||||
<ds-heading tag="h3">
|
||||
Themen / Kategorien
|
||||
{{ $t('admin.categories.name') }}
|
||||
</ds-heading>
|
||||
<ds-table
|
||||
:data="Category"
|
||||
:fields="['icon', 'name', 'postCount']"
|
||||
:fields="fields"
|
||||
condensed
|
||||
>
|
||||
<template
|
||||
@ -27,6 +27,18 @@ export default {
|
||||
Category: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fields() {
|
||||
return {
|
||||
icon: ' ',
|
||||
name: this.$t('admin.categories.categoryName'),
|
||||
postCount: {
|
||||
label: this.$t('admin.categories.postCount'),
|
||||
align: 'right'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
Category: {
|
||||
query: gql(`
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<ds-space margin="small">
|
||||
<ds-number
|
||||
:count="0"
|
||||
label="Users"
|
||||
:label="$t('admin.dashboard.users')"
|
||||
size="x-large"
|
||||
uppercase
|
||||
>
|
||||
@ -24,7 +24,7 @@
|
||||
<ds-space margin="small">
|
||||
<ds-number
|
||||
:count="0"
|
||||
label="Posts"
|
||||
:label="$t('admin.dashboard.posts')"
|
||||
size="x-large"
|
||||
uppercase
|
||||
>
|
||||
@ -41,7 +41,7 @@
|
||||
<ds-space margin="small">
|
||||
<ds-number
|
||||
:count="0"
|
||||
label="Comments"
|
||||
:label="$t('admin.dashboard.comments')"
|
||||
size="x-large"
|
||||
uppercase
|
||||
>
|
||||
@ -58,7 +58,7 @@
|
||||
<ds-space margin="small">
|
||||
<ds-number
|
||||
:count="0"
|
||||
label="Notifications"
|
||||
:label="$t('admin.dashboard.notifications')"
|
||||
size="x-large"
|
||||
uppercase
|
||||
>
|
||||
@ -75,7 +75,7 @@
|
||||
<ds-space margin="small">
|
||||
<ds-number
|
||||
:count="0"
|
||||
label="Organization"
|
||||
:label="$t('admin.dashboard.organizations')"
|
||||
size="x-large"
|
||||
uppercase
|
||||
>
|
||||
@ -92,7 +92,7 @@
|
||||
<ds-space margin="small">
|
||||
<ds-number
|
||||
:count="0"
|
||||
label="Projects"
|
||||
:label="$t('admin.dashboard.projects')"
|
||||
size="x-large"
|
||||
uppercase
|
||||
>
|
||||
@ -109,7 +109,7 @@
|
||||
<ds-space margin="small">
|
||||
<ds-number
|
||||
:count="0"
|
||||
label="Open Invites"
|
||||
:label="$t('admin.dashboard.invites')"
|
||||
size="x-large"
|
||||
uppercase
|
||||
>
|
||||
@ -126,7 +126,7 @@
|
||||
<ds-space margin="small">
|
||||
<ds-number
|
||||
:count="0"
|
||||
label="Follows"
|
||||
:label="$t('admin.dashboard.follows')"
|
||||
size="x-large"
|
||||
uppercase
|
||||
>
|
||||
@ -143,7 +143,7 @@
|
||||
<ds-space margin="small">
|
||||
<ds-number
|
||||
:count="0"
|
||||
label="Shouts"
|
||||
:label="$t('admin.dashboard.shouts')"
|
||||
size="x-large"
|
||||
uppercase
|
||||
>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ds-card>
|
||||
<ds-space margin="small">
|
||||
Notifications...
|
||||
</ds-space>
|
||||
<ds-card space="small">
|
||||
<ds-heading tag="h3">
|
||||
{{ $t('admin.notifications.name') }}
|
||||
</ds-heading>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ds-card>
|
||||
<ds-space margin="small">
|
||||
Organizations...
|
||||
{{ $t('admin.organizations.name') }}
|
||||
</ds-space>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ds-card>
|
||||
<ds-space margin="small">
|
||||
Pages...
|
||||
{{ $t('admin.pages.name') }}
|
||||
</ds-space>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ds-card>
|
||||
<ds-space margin="small">
|
||||
Settings...
|
||||
{{ $t('admin.settings.name') }}
|
||||
</ds-space>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ds-card space="small">
|
||||
<ds-heading tag="h3">
|
||||
Tags
|
||||
{{ $t('admin.tags.name') }}
|
||||
</ds-heading>
|
||||
<ds-table
|
||||
:data="Tag"
|
||||
@ -24,12 +24,22 @@ import gql from 'graphql-tag'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
Tag: [],
|
||||
fields: {
|
||||
id: { label: '#' },
|
||||
name: { label: 'Name' },
|
||||
taggedCountUnique: { label: 'Nutzer' },
|
||||
taggedCount: { label: 'Beiträge' }
|
||||
Tag: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fields() {
|
||||
return {
|
||||
id: '#',
|
||||
name: 'Name',
|
||||
taggedCountUnique: {
|
||||
label: this.$t('admin.tags.tagCountUnique'),
|
||||
align: 'right'
|
||||
},
|
||||
taggedCount: {
|
||||
label: this.$t('admin.tags.tagCount'),
|
||||
align: 'right'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ds-card>
|
||||
<ds-space margin="small">
|
||||
Users...
|
||||
{{ $t('admin.users.name') }}
|
||||
</ds-space>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
184
pages/login.vue
@ -1,93 +1,112 @@
|
||||
<template>
|
||||
<ds-container width="small">
|
||||
<ds-space margin="small">
|
||||
<blockquote>
|
||||
<p>
|
||||
Viele kleine Leute, an vielen kleinen Orten, die viele kleine Dinge tun, werden das Antlitz dieser Welt verändern.
|
||||
</p>
|
||||
<b>- Afrikanisches Sprichwort</b>
|
||||
</blockquote>
|
||||
</ds-space>
|
||||
<ds-card>
|
||||
<ds-flex gutter="small">
|
||||
<ds-flex-item
|
||||
:width="{ base: '100%', sm: '50%' }"
|
||||
center
|
||||
>
|
||||
<ds-space
|
||||
margin-top="small"
|
||||
margin-bottom="xxx-small"
|
||||
<transition
|
||||
name="fade"
|
||||
appear
|
||||
>
|
||||
<ds-container
|
||||
v-if="ready"
|
||||
width="small"
|
||||
>
|
||||
<ds-space margin="small">
|
||||
<blockquote>
|
||||
<p>{{ $t('quotes.african.quote') }}</p>
|
||||
<b>- {{ $t('quotes.african.author') }}</b>
|
||||
</blockquote>
|
||||
</ds-space>
|
||||
<ds-card class="login-card">
|
||||
<ds-flex gutter="small">
|
||||
<ds-flex-item
|
||||
:width="{ base: '100%', sm: '50%' }"
|
||||
center
|
||||
>
|
||||
<img
|
||||
class="login-image"
|
||||
src="/img/sign-up/humanconnection.svg"
|
||||
alt="Human Connection"
|
||||
<no-ssr>
|
||||
<locale-switch
|
||||
class="login-locale-switch"
|
||||
offset="5"
|
||||
/>
|
||||
</no-ssr>
|
||||
<ds-space
|
||||
margin-top="small"
|
||||
margin-bottom="xxx-small"
|
||||
center
|
||||
>
|
||||
</ds-space>
|
||||
</ds-flex-item>
|
||||
<ds-flex-item
|
||||
:width="{ base: '100%', sm: '50%' }"
|
||||
center
|
||||
>
|
||||
<ds-space margin="small">
|
||||
<ds-text size="small">
|
||||
Wenn Du ein Konto bei Human Connection hast, melde Dich bitte hier an.
|
||||
</ds-text>
|
||||
</ds-space>
|
||||
<form
|
||||
:disabled="pending"
|
||||
@submit.prevent="onSubmit"
|
||||
>
|
||||
<ds-input
|
||||
v-model="form.email"
|
||||
:disabled="pending"
|
||||
placeholder="Deine E-Mail"
|
||||
type="email"
|
||||
name="email"
|
||||
icon="envelope"
|
||||
/>
|
||||
<ds-input
|
||||
v-model="form.password"
|
||||
:disabled="pending"
|
||||
placeholder="Dein Password"
|
||||
icon="lock"
|
||||
icon-right="question-circle"
|
||||
name="password"
|
||||
type="password"
|
||||
/>
|
||||
<ds-button
|
||||
:loading="pending"
|
||||
primary
|
||||
full-width
|
||||
name="submit"
|
||||
type="submit"
|
||||
>
|
||||
Anmelden
|
||||
</ds-button>
|
||||
<ds-space margin="x-small">
|
||||
<a
|
||||
href="https://human-connection.org"
|
||||
title="zur Präsentationsseite"
|
||||
target="_blank"
|
||||
<img
|
||||
class="login-image"
|
||||
src="/img/sign-up/humanconnection.svg"
|
||||
alt="Human Connection"
|
||||
>
|
||||
Was ist Human Connection?
|
||||
</a>
|
||||
</ds-space>
|
||||
</form>
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
</ds-card>
|
||||
</ds-container>
|
||||
</ds-flex-item>
|
||||
<ds-flex-item
|
||||
:width="{ base: '100%', sm: '50%' }"
|
||||
center
|
||||
>
|
||||
<ds-space margin="small">
|
||||
<ds-text size="small">
|
||||
{{ $t('login.copy') }}
|
||||
</ds-text>
|
||||
</ds-space>
|
||||
<form
|
||||
:disabled="pending"
|
||||
@submit.prevent="onSubmit"
|
||||
>
|
||||
<ds-input
|
||||
v-model="form.email"
|
||||
:disabled="pending"
|
||||
:placeholder="$t('login.email')"
|
||||
type="email"
|
||||
name="email"
|
||||
icon="envelope"
|
||||
/>
|
||||
<ds-input
|
||||
v-model="form.password"
|
||||
:disabled="pending"
|
||||
:placeholder="$t('login.password')"
|
||||
icon="lock"
|
||||
icon-right="question-circle"
|
||||
name="password"
|
||||
type="password"
|
||||
/>
|
||||
<ds-button
|
||||
:loading="pending"
|
||||
primary
|
||||
full-width
|
||||
name="submit"
|
||||
type="submit"
|
||||
icon="sign-in"
|
||||
>
|
||||
{{ $t('login.login') }}
|
||||
</ds-button>
|
||||
<ds-space margin="x-small">
|
||||
<a
|
||||
href="https://human-connection.org"
|
||||
title="zur Präsentationsseite"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $t('login.moreInfo') }}
|
||||
</a>
|
||||
</ds-space>
|
||||
</form>
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
</ds-card>
|
||||
</ds-container>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LocaleSwitch from '~/components/LocaleSwitch'
|
||||
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
LocaleSwitch
|
||||
},
|
||||
layout: 'blank',
|
||||
data() {
|
||||
return {
|
||||
ready: false,
|
||||
form: {
|
||||
email: '',
|
||||
password: ''
|
||||
@ -104,6 +123,13 @@ export default {
|
||||
return this.$store.getters['auth/pending']
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
setTimeout(() => {
|
||||
// NOTE: quick fix for jumping flexbox implementation
|
||||
// will be fixed in a future update of the styleguide
|
||||
this.ready = true
|
||||
}, 50)
|
||||
},
|
||||
methods: {
|
||||
async onSubmit() {
|
||||
try {
|
||||
@ -123,4 +149,12 @@ export default {
|
||||
width: 90%;
|
||||
max-width: 200px;
|
||||
}
|
||||
.login-card {
|
||||
position: relative;
|
||||
}
|
||||
.login-locale-switch {
|
||||
position: absolute;
|
||||
top: 1em;
|
||||
left: 1em;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
color="soft"
|
||||
size="small"
|
||||
>
|
||||
Mitglied seit {{ user.createdAt | date('MMMM yyyy') }}
|
||||
{{ $t('profile.memberSince') }} {{ user.createdAt | date('MMMM yyyy') }}
|
||||
</ds-text>
|
||||
</ds-space>
|
||||
<ds-space
|
||||
@ -44,7 +44,7 @@
|
||||
<ds-flex>
|
||||
<ds-flex-item>
|
||||
<no-ssr>
|
||||
<ds-number label="Folgen">
|
||||
<ds-number :label="$t('profile.following')">
|
||||
<hc-count-to
|
||||
slot="count"
|
||||
:end-val="followedByCount"
|
||||
@ -54,7 +54,7 @@
|
||||
</ds-flex-item>
|
||||
<ds-flex-item>
|
||||
<no-ssr>
|
||||
<ds-number label="Folgt">
|
||||
<ds-number :label="$t('profile.followers')">
|
||||
<hc-count-to
|
||||
slot="count"
|
||||
:end-val="Number(user.followingCount) || 0"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<ds-heading tag="h1">
|
||||
Settings
|
||||
{{ $t('settings.name') }}
|
||||
</ds-heading>
|
||||
<ds-flex gutter="small">
|
||||
<ds-flex-item :width="{ base: '200px' }">
|
||||
@ -21,36 +21,36 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
routes: [
|
||||
computed: {
|
||||
routes() {
|
||||
return [
|
||||
{
|
||||
name: 'Your Data',
|
||||
name: this.$t('settings.data.name'),
|
||||
path: `/settings`
|
||||
},
|
||||
{
|
||||
name: 'Password',
|
||||
path: `/settings/password`
|
||||
name: this.$t('settings.security.name'),
|
||||
path: `/settings/security`
|
||||
},
|
||||
{
|
||||
name: 'Invites',
|
||||
name: this.$t('settings.invites.name'),
|
||||
path: `/settings/invites`
|
||||
},
|
||||
{
|
||||
name: 'Data Download',
|
||||
name: this.$t('settings.download.name'),
|
||||
path: `/settings/data-download`
|
||||
},
|
||||
{
|
||||
name: 'Delete Account',
|
||||
name: this.$t('settings.delete.name'),
|
||||
path: `/settings/delete-account`
|
||||
},
|
||||
{
|
||||
name: 'My Organizations',
|
||||
name: this.$t('settings.organizations.name'),
|
||||
path: `/settings/my-organizations`
|
||||
},
|
||||
{
|
||||
name: 'Settings',
|
||||
path: `/settings/settings`
|
||||
name: this.$t('settings.languages.name'),
|
||||
path: `/settings/languages`
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ds-card>
|
||||
<ds-space margin="small">
|
||||
Download my Data...
|
||||
{{ $t('settings.download.name') }}
|
||||
</ds-space>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ds-card>
|
||||
<ds-space margin="small">
|
||||
Delete my Account...
|
||||
{{ $t('settings.delete.name') }}
|
||||
</ds-space>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<ds-card>
|
||||
<p>My Data...</p>
|
||||
<ds-space margin="small">
|
||||
{{ $t('settings.data.name') }}
|
||||
</ds-space>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ds-card>
|
||||
<ds-space margin="small">
|
||||
Invites...
|
||||
{{ $t('settings.invites.name') }}
|
||||
</ds-space>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ds-card>
|
||||
<ds-space margin="small">
|
||||
Settings...
|
||||
{{ $t('settings.languages.name') }}
|
||||
</ds-space>
|
||||
</ds-card>
|
||||
</template>
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ds-card>
|
||||
<ds-space margin="small">
|
||||
My Organizations...
|
||||
{{ $t('settings.organizations.name') }}
|
||||
</ds-space>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ds-card>
|
||||
<ds-space margin="small">
|
||||
Change my Password...
|
||||
{{ $t('settings.security.name') }}
|
||||
</ds-space>
|
||||
</ds-card>
|
||||
</template>
|
||||
102
plugins/i18n.js
Normal file
@ -0,0 +1,102 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import vuexI18n from 'vuex-i18n/dist/vuex-i18n.umd.js'
|
||||
import { debounce, isEmpty, find } from 'lodash'
|
||||
|
||||
/**
|
||||
* TODO: Refactor and simplify browser detection
|
||||
* and implement the user preference logic
|
||||
*/
|
||||
export default ({ app, req, cookie, store }) => {
|
||||
const debug = app.$env.NODE_ENV !== 'production'
|
||||
const key = 'locale'
|
||||
|
||||
const changeHandler = async mutation => {
|
||||
if (process.server) return
|
||||
|
||||
const newLocale = mutation.payload.locale
|
||||
const currentLocale = await app.$cookies.get(key)
|
||||
const isDifferent = newLocale !== currentLocale
|
||||
|
||||
if (!isDifferent) {
|
||||
return
|
||||
}
|
||||
|
||||
app.$cookies.set(key, newLocale)
|
||||
if (!app.$i18n.localeExists(newLocale)) {
|
||||
import(`~/locales/${newLocale}.json`).then(res => {
|
||||
app.$i18n.add(newLocale, res.default)
|
||||
})
|
||||
}
|
||||
|
||||
const user = store.getters['auth/user']
|
||||
const token = store.getters['auth/token']
|
||||
// persist language if it differs from last value
|
||||
if (user && user._id && token) {
|
||||
// TODO: SAVE LOCALE
|
||||
// store.dispatch('usersettings/patch', {
|
||||
// uiLanguage: newLocale
|
||||
// }, { root: true })
|
||||
}
|
||||
}
|
||||
|
||||
// const i18nStore = new Vuex.Store({
|
||||
// strict: debug
|
||||
// })
|
||||
|
||||
Vue.use(vuexI18n.plugin, store, {
|
||||
onTranslationNotFound: function(locale, key) {
|
||||
if (debug) {
|
||||
console.warn(
|
||||
`vuex-i18n :: Key '${key}' not found for locale '${locale}'`
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// register the fallback locales
|
||||
Vue.i18n.add('en', require('~/locales/en.json'))
|
||||
|
||||
let userLocale = 'en'
|
||||
const localeCookie = app.$cookies.get(key)
|
||||
/* const userSettings = store.getters['auth/userSettings']
|
||||
if (userSettings && userSettings.uiLanguage) {
|
||||
// try to get saved user preference
|
||||
userLocale = userSettings.uiLanguage
|
||||
} else */
|
||||
if (!isEmpty(localeCookie)) {
|
||||
userLocale = localeCookie
|
||||
} else {
|
||||
userLocale = process.browser
|
||||
? navigator.language || navigator.userLanguage
|
||||
: req.locale
|
||||
if (userLocale && !isEmpty(userLocale.language)) {
|
||||
userLocale = userLocale.language.substr(0, 2)
|
||||
}
|
||||
}
|
||||
|
||||
const availableLocales = process.env.locales.filter(lang => !!lang.enabled)
|
||||
const locale = find(availableLocales, ['code', userLocale])
|
||||
? userLocale
|
||||
: 'en'
|
||||
|
||||
if (locale !== 'en') {
|
||||
Vue.i18n.add(locale, require(`~/locales/${locale}.json`))
|
||||
}
|
||||
|
||||
// Set the start locale to use
|
||||
Vue.i18n.set(locale)
|
||||
Vue.i18n.fallback('en')
|
||||
|
||||
if (process.browser) {
|
||||
store.subscribe(mutation => {
|
||||
if (mutation.type === 'i18n/SET_LOCALE') {
|
||||
changeHandler(mutation)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
app.$i18n = Vue.i18n
|
||||
|
||||
return store
|
||||
}
|
||||
@ -1,25 +1,44 @@
|
||||
import Vue from 'vue'
|
||||
|
||||
import { en, de } from 'date-fns/locale'
|
||||
import { enUS, de, nl, fr, es } from 'date-fns/locale'
|
||||
import format from 'date-fns/format'
|
||||
import formatRelative from 'date-fns/formatRelative'
|
||||
import addSeconds from 'date-fns/addSeconds'
|
||||
|
||||
import accounting from 'accounting'
|
||||
|
||||
export default ({ app }) => {
|
||||
const locales = {
|
||||
en: enUS,
|
||||
de: de,
|
||||
nl: nl,
|
||||
fr: fr,
|
||||
es: es,
|
||||
pt: es,
|
||||
pl: de
|
||||
}
|
||||
const getLocalizedFormat = () => {
|
||||
let locale = app.$i18n.locale()
|
||||
locale = locales[locale] ? locale : 'en'
|
||||
return locales[locale]
|
||||
}
|
||||
app.$filters = Object.assign(app.$filters || {}, {
|
||||
date: (value, fmt = 'dd. MMM yyyy') => {
|
||||
if (!value) return ''
|
||||
return format(new Date(value), fmt, { locale: de })
|
||||
return format(new Date(value), fmt, {
|
||||
locale: getLocalizedFormat()
|
||||
})
|
||||
},
|
||||
dateTime: (value, fmt = 'dd. MMM yyyy HH:mm') => {
|
||||
if (!value) return ''
|
||||
return format(new Date(value), fmt, { locale: de })
|
||||
return format(new Date(value), fmt, {
|
||||
locale: getLocalizedFormat()
|
||||
})
|
||||
},
|
||||
relativeDateTime: value => {
|
||||
if (!value) return ''
|
||||
return formatRelative(new Date(value), new Date(), { locale: de })
|
||||
return formatRelative(new Date(value), new Date(), {
|
||||
locale: getLocalizedFormat()
|
||||
})
|
||||
},
|
||||
number: (
|
||||
value,
|
||||
|
||||
1
static/img/locale-flags/de.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M16 345a256 256 0 0 0 480 0l-240-22.2L16 345z" fill="#ffda44"/><path d="M256 0A256 256 0 0 0 16 167l240 22.2L496 167A256 256 0 0 0 256 0z"/><path d="M16 167a255.5 255.5 0 0 0 0 178h480a255.4 255.4 0 0 0 0-178H16z" fill="#d80027"/></svg>
|
||||
|
After Width: | Height: | Size: 307 B |
1
static/img/locale-flags/en.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512"><defs><path id="a" d="M0 512L512 0v512z"/></defs><g fill="none" fill-rule="evenodd"><circle cx="256" cy="256" r="256" fill="#F0F0F0"/><path fill="#D80027" fill-rule="nonzero" d="M327.7 189.2H245V256h15.6l67.2-66.8zm146.7-66.8a257.3 257.3 0 0 0-59-66.7H244.9v66.7h229.5zM127.8 389.6l67.4-66.8H8.8c6.4 23.5 16 46 28.8 66.8h90.2z"/><path fill="#0052B4" fill-rule="nonzero" d="M118.6 40h23.3l-21.7 15.7 8.3 25.6-21.7-15.8-21.7 15.8 7.2-22a257.4 257.4 0 0 0-49.7 55.3h7.5l-13.8 10c-2.2 3.6-4.2 7.2-6.2 11l6.6 20.2-12.3-9c-3.1 6.6-5.9 13.2-8.4 20l7.3 22.3H50L28.4 205l8.3 25.5L15 214.6l-13 9.5C.7 234.7 0 245.3 0 256h256V0c-50.6 0-97.7 14.7-137.4 40zm9.9 190.4l-21.7-15.8-21.7 15.8 8.3-25.5L71.7 189h26.8l8.3-25.5 8.3 25.5h26.8L120.2 205l8.3 25.5zm-8.3-100l8.3 25.4-21.7-15.7-21.7 15.7 8.3-25.5-21.7-15.7h26.8l8.3-25.6 8.3 25.6h26.8l-21.7 15.7zm100.1 100l-21.7-15.8-21.7 15.8 8.3-25.5-21.7-15.8h26.8l8.3-25.5 8.3 25.5h26.8L212 205l8.3 25.5zm-8.3-100l8.3 25.4-21.7-15.7-21.7 15.7 8.3-25.5-21.7-15.7h26.8l8.3-25.6 8.3 25.6h26.8L212 130.3zm0-74.7l8.3 25.6-21.7-15.8L177 81.3l8.3-25.6L163.5 40h26.8l8.3-25.5L207 40h26.8L212 55.7z"/><mask id="b" fill="#fff"><use xlink:href="#a"/></mask><g mask="url(#b)"><circle cx="256" cy="256" r="256" fill="#F0F0F0"/><path fill="#0052B4" fill-rule="nonzero" d="M503.2 189.2a255 255 0 0 0-44.1-89l-89.1 89h133.2zm-403 269.9a255 255 0 0 0 89 44V370l-89 89zm222.6 44a255 255 0 0 0 89-44l-89-89.1v133.2zM370 322.9l89 89a255 255 0 0 0 44.2-89H370z"/><path fill="#D80027" d="M509.8 222.6H222.4l.2 287.2c22.2 3 44.6 3 66.8 0V289.4h220.4a258.5 258.5 0 0 0 0-66.8z"/><path fill="#D80027" fill-rule="nonzero" d="M322.8 322.8L437 437c5.3-5.2 10.3-10.7 15-16.4l-97.7-97.8h-31.5zm-133.6 0L75 437c5.2 5.3 10.7 10.3 16.4 15l97.8-97.7v-31.5z"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
1
static/img/locale-flags/es.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M0 256c0 31.3 5.6 61.3 16 89l240 22.3L496 345a255.5 255.5 0 0 0 0-178l-240-22.3L16 167a255.5 255.5 0 0 0-16 89z" fill="#ffda44"/><path d="M496 167a256 256 0 0 0-480 0h480zM16 345a256 256 0 0 0 480 0H16z" fill="#d80027"/></svg>
|
||||
|
After Width: | Height: | Size: 297 B |
1
static/img/locale-flags/fr.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><circle cx="256" cy="256" r="256" fill="#f0f0f0"/><path d="M512 256A256 256 0 0 0 345 16v480a256 256 0 0 0 167-240z" fill="#d80027"/><path d="M0 256a256 256 0 0 0 167 240V16A256 256 0 0 0 0 256z" fill="#0052b4"/></svg>
|
||||
|
After Width: | Height: | Size: 280 B |
1
static/img/locale-flags/it.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><circle cx="256" cy="256" r="256" fill="#f0f0f0"/><path d="M512 256A256 256 0 0 0 345 16v480a256 256 0 0 0 167-240z" fill="#d80027"/><path d="M0 256a256 256 0 0 0 167 240V16A256 256 0 0 0 0 256z" fill="#6da544"/></svg>
|
||||
|
After Width: | Height: | Size: 280 B |
1
static/img/locale-flags/nl.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><circle cx="256" cy="256" r="256" fill="#f0f0f0"/><path d="M256 0A256 256 0 0 0 16 167h480A256 256 0 0 0 256 0z" fill="#a2001d"/><path d="M256 512a256 256 0 0 0 240-167H16a256 256 0 0 0 240 167z" fill="#0052b4"/></svg>
|
||||
|
After Width: | Height: | Size: 280 B |
1
static/img/locale-flags/pl.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><circle cx="256" cy="256" r="256" fill="#f0f0f0"/><path d="M512 256a256 256 0 0 1-512 0" fill="#d80027"/></svg>
|
||||
|
After Width: | Height: | Size: 173 B |
1
static/img/locale-flags/pt.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M0 256a256 256 0 0 0 167 240l22.2-240L167 16A256 256 0 0 0 0 256z" fill="#6da544"/><path d="M512 256A256 256 0 0 0 167 16v480a256 256 0 0 0 345-240z" fill="#d80027"/><circle cx="167" cy="256" r="89" fill="#ffda44"/><path d="M116.9 211.5V267a50 50 0 1 0 100.1 0v-55.6H117z" fill="#d80027"/><path d="M167 283.8c-9.2 0-16.7-7.5-16.7-16.7V245h33.4V267c0 9.2-7.5 16.7-16.7 16.7z" fill="#f0f0f0"/></svg>
|
||||
|
After Width: | Height: | Size: 468 B |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 220 KiB |
|
Before Width: | Height: | Size: 202 KiB After Width: | Height: | Size: 180 KiB |
@ -20,7 +20,8 @@
|
||||
<tr>
|
||||
<ds-table-head-col
|
||||
v-for="header in headers"
|
||||
:key="header.key">
|
||||
:key="header.key"
|
||||
:align="align(header.key)">
|
||||
{{ header.label }}
|
||||
</ds-table-head-col>
|
||||
</tr>
|
||||
@ -31,7 +32,8 @@
|
||||
:key="row.key || index">
|
||||
<ds-table-col
|
||||
v-for="col in row"
|
||||
:key="col.key">
|
||||
:key="col.key"
|
||||
:align="align(col.key)">
|
||||
<!-- @slot Slots are named by fields -->
|
||||
<slot
|
||||
:name="col.key"
|
||||
@ -152,6 +154,9 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
align(colKey) {
|
||||
return this.fields && this.fields[colKey] ? this.fields[colKey].align : null
|
||||
},
|
||||
parseLabel(label) {
|
||||
return startCase(label)
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<td class="ds-table-col">
|
||||
<!-- eslint-disable -->
|
||||
<td
|
||||
class="ds-table-col"
|
||||
:class="[
|
||||
align && `ds-table-col-${align}`
|
||||
]">
|
||||
<slot/>
|
||||
</td>
|
||||
</template>
|
||||
@ -25,6 +30,17 @@ export default {
|
||||
width: {
|
||||
type: [String, Number, Object],
|
||||
default: null
|
||||
},
|
||||
/**
|
||||
* The column align
|
||||
* `left, center, right`
|
||||
*/
|
||||
align: {
|
||||
type: String,
|
||||
default: null,
|
||||
validator: value => {
|
||||
return value.match(/(left|center|right)/)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {}
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
<template>
|
||||
<th class="ds-table-head-col">
|
||||
<th
|
||||
class="ds-table-head-col"
|
||||
:class="[
|
||||
align && `ds-table-head-col-${align}`
|
||||
]">
|
||||
<slot>
|
||||
{{ label }}
|
||||
</slot>
|
||||
@ -36,6 +40,17 @@ export default {
|
||||
width: {
|
||||
type: [String, Number, Object],
|
||||
default: null
|
||||
},
|
||||
/**
|
||||
* The column align
|
||||
* `left, center, right`
|
||||
*/
|
||||
align: {
|
||||
type: String,
|
||||
default: null,
|
||||
validator: value => {
|
||||
return value.match(/(left|center|right)/)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {}
|
||||
|
||||
@ -100,7 +100,8 @@ The value can be a string representing the fields label or an object with option
|
||||
name: 'Hero',
|
||||
type: {
|
||||
label: 'Job',
|
||||
width: '300px'
|
||||
width: '300px',
|
||||
align: 'right'
|
||||
}
|
||||
},
|
||||
tableData: [
|
||||
@ -191,4 +192,4 @@ Via scoped slots you have access to the columns `row`, `index` and `col`.
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
```
|
||||
|
||||
@ -42,3 +42,19 @@
|
||||
padding-bottom: $space-x-small;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-table-col,
|
||||
.ds-table-head-col {
|
||||
&.ds-table-col-left,
|
||||
&.ds-table-head-col-left {
|
||||
text-align: left;
|
||||
}
|
||||
&.ds-table-col-center,
|
||||
&.ds-table-head-col-center {
|
||||
text-align: center;
|
||||
}
|
||||
&.ds-table-col-right,
|
||||
&.ds-table-head-col-right {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,7 +46,10 @@ export default {
|
||||
default: null
|
||||
},
|
||||
|
||||
align: {
|
||||
/**
|
||||
* Center content vertacally and horizontally
|
||||
*/
|
||||
center: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
|
||||
@ -44,6 +44,7 @@ ul.ds-menu-list {
|
||||
text-decoration: none;
|
||||
padding: $space-x-small $space-small;
|
||||
transition: color $duration-short $ease-out;
|
||||
border-left: 2px solid transparent;
|
||||
|
||||
&.router-link-active,
|
||||
&.nuxt-link-active {
|
||||
@ -56,8 +57,9 @@ ul.ds-menu-list {
|
||||
|
||||
&.router-link-exact-active,
|
||||
&.nuxt-link-exact-active {
|
||||
color: $text-color-link-active;
|
||||
background-color: $background-color-soft;
|
||||
color: $text-color-link;
|
||||
// background-color: $background-color-soft;
|
||||
border-left: 2px solid $color-primary;
|
||||
}
|
||||
|
||||
.ds-menu-item-inverse & {
|
||||
|
||||
25
yarn.lock
@ -1225,6 +1225,11 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/cookie@^0.3.1":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.3.2.tgz#453f4b14b25da6a8ea4494842dedcbf0151deef9"
|
||||
integrity sha512-aHQA072E10/8iUQsPH7mQU/KUyQBZAGzTVRCUvnSz8mSvbrYsP4xEO2RSA0Pjltolzi0j8+8ixrm//Hr4umPzw==
|
||||
|
||||
"@types/cors@^2.8.4":
|
||||
version "2.8.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.4.tgz#50991a759a29c0b89492751008c6af7a7c8267b0"
|
||||
@ -3788,6 +3793,21 @@ cookie-signature@1.0.6:
|
||||
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
|
||||
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
|
||||
|
||||
cookie-universal-nuxt@^2.0.11:
|
||||
version "2.0.11"
|
||||
resolved "https://registry.yarnpkg.com/cookie-universal-nuxt/-/cookie-universal-nuxt-2.0.11.tgz#f7f2ea1d63a497b24d5e630cee4e999475e777f4"
|
||||
integrity sha512-GmzXjkIpCRAe+fIpYavHyFliEDRofiJMbBd17kZJia+nLVEt2CJxjOqcQRqUOXmvtuB0oHDYy+fVflxs863T0w==
|
||||
dependencies:
|
||||
"@types/cookie" "^0.3.1"
|
||||
cookie-universal "^2.0.11"
|
||||
|
||||
cookie-universal@^2.0.11:
|
||||
version "2.0.11"
|
||||
resolved "https://registry.yarnpkg.com/cookie-universal/-/cookie-universal-2.0.11.tgz#525f6324b6698a713b46be77a3440daff68e4a6a"
|
||||
integrity sha512-5IA+uAPwBuphUfuk+lpFEajfrUTZA3RmMXfoT/KWs29WMd2ZifHOafAr+w8WdlSixddjTEkOgUWrk27+ErueUg==
|
||||
dependencies:
|
||||
cookie "^0.3.1"
|
||||
|
||||
cookie@0.3.1, cookie@^0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
|
||||
@ -11662,6 +11682,11 @@ vue@^2.5.17:
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.17.tgz#0f8789ad718be68ca1872629832ed533589c6ada"
|
||||
integrity sha512-mFbcWoDIJi0w0Za4emyLiW72Jae0yjANHbCVquMKijcavBGypqlF7zHRgMa5k4sesdv7hv2rB4JPdZfR+TPfhQ==
|
||||
|
||||
vuex-i18n@^1.10.5:
|
||||
version "1.10.5"
|
||||
resolved "https://registry.yarnpkg.com/vuex-i18n/-/vuex-i18n-1.10.5.tgz#635ea2204e0aa3f8fd512f0fab7f6b994d3f666c"
|
||||
integrity sha1-Y16iIE4Ko/j9US8Pq39rmU0/Zmw=
|
||||
|
||||
vuex@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.0.1.tgz#e761352ebe0af537d4bb755a9b9dc4be3df7efd2"
|
||||
|
||||