Merge branch 'dev' into oauth2

This commit is contained in:
Sam
2022-07-03 19:05:38 +02:00
176 changed files with 3782 additions and 2122 deletions

View File

@ -1,6 +1,6 @@
{
"name": "fittrackee_client",
"version": "0.6.8",
"version": "0.6.9",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
@ -20,7 +20,7 @@
"axios": "^0.26.1",
"chart.js": "^3.8.0",
"chartjs-plugin-datalabels": "^2.0.0",
"core-js": "^3.23.2",
"core-js": "^3.23.3",
"date-fns": "^2.28.0",
"date-fns-tz": "^1.3.5",
"leaflet": "^1.8.0",
@ -36,8 +36,8 @@
"@intlify/vue-i18n-loader": "^4.2.0",
"@types/chai": "^4.3.1",
"@types/mocha": "^9.1.1",
"@typescript-eslint/eslint-plugin": "^5.29.0",
"@typescript-eslint/parser": "^5.29.0",
"@typescript-eslint/eslint-plugin": "^5.30.4",
"@typescript-eslint/parser": "^5.30.4",
"@vue/cli-plugin-babel": "~5.0.6",
"@vue/cli-plugin-eslint": "~5.0.6",
"@vue/cli-plugin-pwa": "~5.0.6",
@ -49,15 +49,15 @@
"@vue/eslint-config-typescript": "^11.0.0",
"@vue/test-utils": "^2.0.0",
"chai": "^4.3.6",
"eslint": "^8.18.0",
"eslint": "^8.19.0",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^2.7.1",
"eslint-import-resolver-typescript": "^3.2.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.1.1",
"prettier": "^2.7.1",
"sass": "^1.52.3",
"sass-loader": "^13.0.0",
"sass": "^1.53.0",
"sass-loader": "^13.0.2",
"typescript": "^4.7.4",
"vue-cli-plugin-i18n": "~2.3.1"
},

View File

@ -35,6 +35,7 @@
import { ROOT_STORE } from '@/store/constants'
import { TAppConfig } from '@/types/application'
import { useStore } from '@/use/useStore'
import { localeFromLanguage } from '@/utils/locales'
const store = useStore()
@ -47,7 +48,10 @@
const hideScrollBar = ref(false)
const displayScrollButton = ref(false)
onBeforeMount(() => store.dispatch(ROOT_STORE.ACTIONS.GET_APPLICATION_CONFIG))
onBeforeMount(() => {
initLanguage()
store.dispatch(ROOT_STORE.ACTIONS.GET_APPLICATION_CONFIG)
})
onMounted(() => scroll())
function updateHideScrollBar(isMenuOpen: boolean) {
@ -74,6 +78,18 @@
displayScrollButton.value = false
}, 300)
}
function initLanguage() {
let language = 'en'
try {
const navigatorLanguage = navigator.language.split('-')[0]
if (navigatorLanguage in localeFromLanguage) {
language = navigatorLanguage
}
} catch (e) {
language = 'en'
}
store.dispatch(ROOT_STORE.ACTIONS.UPDATE_APPLICATION_LANGUAGE, language)
}
</script>
<style lang="scss">

View File

@ -6,9 +6,13 @@
{{ sportTranslatedLabel }}
</template>
<template #content>
<div class="record" v-for="record in records.records" :key="record.id">
<div
class="record"
v-for="record in getTranslatedRecords(records.records)"
:key="record.id"
>
<span class="record-type">
{{ $t(`workouts.RECORD_${record.record_type}`) }}
{{ record.label }}
</span>
<span class="record-value">{{ record.value }}</span>
<span class="record-date">
@ -29,8 +33,10 @@
<script setup lang="ts">
import { toRefs } from 'vue'
import { useI18n } from 'vue-i18n'
import { IRecordsBySports } from '@/types/workouts'
import { ICardRecord, IRecord, IRecordsBySports } from '@/types/workouts'
import { sortRecords } from '@/utils/records'
interface Props {
records: IRecordsBySports
@ -39,6 +45,19 @@
const props = defineProps<Props>()
const { records, sportTranslatedLabel } = toRefs(props)
const { t } = useI18n()
function getTranslatedRecords(records: IRecord[]): ICardRecord[] {
const translatedRecords: ICardRecord[] = []
records.map((record) => {
translatedRecords.push({
...record,
label: t(`workouts.RECORD_${record.record_type}`),
})
})
return translatedRecords.sort(sortRecords)
}
</script>
<style lang="scss" scoped>
@ -64,6 +83,7 @@
padding: $default-padding;
.record {
display: flex;
align-items: center;
justify-content: space-between;
span {
padding: 2px 5px;
@ -73,6 +93,7 @@
}
.record-value {
font-weight: bold;
white-space: nowrap;
padding-right: $default-padding * 2;
}
}

View File

@ -25,13 +25,13 @@
import RecordsCard from '@/components/Dashboard/UserRecords/RecordsCard.vue'
import { ISport } from '@/types/sports'
import { IUserProfile } from '@/types/user'
import { IAuthUserProfile } from '@/types/user'
import { getRecordsBySports } from '@/utils/records'
import { translateSports } from '@/utils/sports'
interface Props {
sports: ISport[]
user: IUserProfile
user: IAuthUserProfile
}
const props = defineProps<Props>()

View File

@ -79,7 +79,6 @@
<script setup lang="ts">
import { ComputedRef, computed, ref, capitalize } from 'vue'
import { useI18n } from 'vue-i18n'
import UserPicture from '@/components/User/UserPicture.vue'
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
@ -90,7 +89,6 @@
const emit = defineEmits(['menuInteraction'])
const { locale } = useI18n()
const store = useStore()
const authUser: ComputedRef<IAuthUserProfile> = computed(
@ -113,8 +111,10 @@
emit('menuInteraction', false)
}
function updateLanguage(option: IDropdownOption) {
locale.value = option.value.toString()
store.commit(ROOT_STORE.MUTATIONS.UPDATE_LANG, option.value)
store.dispatch(
ROOT_STORE.ACTIONS.UPDATE_APPLICATION_LANGUAGE,
option.value.toString()
)
}
function logout() {
store.dispatch(AUTH_USER_STORE.ACTIONS.LOGOUT)

View File

@ -191,6 +191,9 @@
const appConfig: ComputedRef<TAppConfig> = computed(
() => store.getters[ROOT_STORE.GETTERS.APP_CONFIG]
)
const language: ComputedRef<string> = computed(
() => store.getters[ROOT_STORE.GETTERS.LANGUAGE]
)
const registration_disabled: ComputedRef<boolean> = computed(
() =>
props.action === 'register' && !appConfig.value.is_registration_enabled
@ -245,6 +248,7 @@
}
)
default:
formData['language'] = language.value
store.dispatch(AUTH_USER_STORE.ACTIONS.LOGIN_OR_REGISTER, {
actionType,
formData,

View File

@ -25,7 +25,7 @@
:query="query"
/>
<table>
<thead>
<thead :class="{ smaller: 'de' === currentLanguage }">
<tr>
<th class="sport-col" />
<th>{{ capitalize($t('workouts.WORKOUT', 1)) }}</th>
@ -79,7 +79,7 @@
:display-hover="true"
/>
</td>
<td>
<td class="workout-date">
<span class="cell-heading">
{{ $t('workouts.DATE') }}
</span>
@ -179,7 +179,7 @@
import Pagination from '@/components/Common/Pagination.vue'
import StaticMap from '@/components/Common/StaticMap.vue'
import NoWorkouts from '@/components/Workouts/NoWorkouts.vue'
import { WORKOUTS_STORE } from '@/store/constants'
import { ROOT_STORE, WORKOUTS_STORE } from '@/store/constants'
import { IPagination } from '@/types/api'
import { ITranslatedSport } from '@/types/sports'
import { IAuthUserProfile } from '@/types/user'
@ -214,6 +214,9 @@
const pagination: ComputedRef<IPagination> = computed(
() => store.getters[WORKOUTS_STORE.GETTERS.WORKOUTS_PAGINATION]
)
const currentLanguage: ComputedRef<string> = computed(
() => store.getters[ROOT_STORE.GETTERS.LANGUAGE]
)
let query: TWorkoutsPayload = getWorkoutsQuery(route.query)
const hoverWorkoutId: Ref<string | null> = ref(null)
@ -238,9 +241,14 @@
}
function getWorkoutsQuery(newQuery: LocationQuery): TWorkoutsPayload {
const workoutQuery = getQuery(newQuery, orderByList, defaultOrder.order_by, {
defaultSort: defaultOrder.order,
})
const workoutQuery = getQuery(
newQuery,
orderByList,
defaultOrder.order_by,
{
defaultSort: defaultOrder.order,
}
)
Object.keys(newQuery)
.filter((k) => workoutsPayloadKeys.includes(k))
.map((k) => {
@ -287,7 +295,7 @@
width: 100%;
.box {
padding: $default-padding $default-padding * 2;
padding: $default-padding $default-padding * 1.5;
@media screen and (max-width: $small-limit) {
&.empty-table {
display: none;
@ -318,11 +326,22 @@
}
.workouts-table {
.smaller {
th {
font-size: 0.95em;
padding: $default-padding 0;
max-width: 100px;
}
}
td {
text-align: right;
}
.sport-col {
padding-right: 0;
padding: 0;
}
.workout-title {
max-width: 90px;
text-align: left;
width: 100px;
position: relative;
.fa-map-o {
font-size: 0.75em;
@ -347,14 +366,27 @@
height: 20px;
width: 20px;
}
.workout-date {
max-width: 60px;
text-align: left;
}
@media screen and (max-width: $small-limit) {
td,
.workout-date,
.workout-title {
text-align: center;
}
.sport-col {
display: flex;
justify-content: center;
padding: $default-padding;
}
.workout-date {
max-width: initial;
}
.workout-title {
max-width: initial;
width: 100%;
}
.workout-title:hover .static-map {
display: none;

View File

@ -0,0 +1,6 @@
{
"CONTACT_ADMIN": "Kontaktiere den Administrator",
"FITTRACKEE_DESCRIPTION": "<strong>FitTrackee</strong> ist ein selbst-gehosteter Outdoor-Aktivitäts-Tracker.",
"FITTRACKEE_LICENSE": "unter {0} Lizenz",
"SOURCE_CODE": "Quellkode"
}

View File

@ -0,0 +1,59 @@
{
"ACTION": "Aktion",
"ACTIVATE_USER_ACCOUNT": "Aktiviere Konto",
"ACTIVE": "Aktiv",
"ADMIN_RIGHTS_DELETE_USER_ACCOUNT": "Hinzufügen/Entfernen von Administratorrechten, Lösche Nutzerkonto.",
"ADMIN": "Admin",
"ADMINISTRATION": "Administration",
"APPLICATION": "Anwendung",
"APP_CONFIG": {
"ADMIN_CONTACT": "Kontakt-E-Mail des Administrators",
"MAX_USERS_LABEL": "Max. Anzahl aktiver Nutzer",
"MAX_USERS_HELP": "Wenn 0, gibt es keine Registrierungslimitierung..",
"MAX_FILES_IN_ZIP_LABEL": "Max. Dateianzahl im zip Archiv",
"NO_CONTACT_EMAIL": "keine Kontakt-E-Mail",
"SINGLE_UPLOAD_MAX_SIZE_LABEL": "Max. Größe der hochgeladenen Dateien (in Mb)",
"TITLE": "Anwendungskonfiguration",
"ZIP_UPLOAD_MAX_SIZE_LABEL": "Max. Größe des zip Archives (in Mb)"
},
"BACK_TO_ADMIN": "Zurück zu Admin",
"CONFIRM_USER_ACCOUNT_DELETION": "Möchtest du wirklich das {0} Konto löschen? Alle Daten werden gelöscht. Dieser Vorgang kann nicht rückgängig gemacht werden.",
"CONFIRM_USER_PASSWORD_RESET": "Möchtest du wirklich das {0} Passwort zurücksetzen?",
"CURRENT_EMAIL": "Aktuelle E-Mail",
"DELETE_USER": "Lösche Nutzer",
"EMAIL_SENDING_DISABLED": "E-Mail-Versand ist deaktiviert.",
"ENABLE_DISABLE_SPORTS": "Aktivieren/Deaktivieren von Sportarten.",
"NEW_EMAIL": "Neue E-Mail",
"PASSWORD_RESET_SUCCESSFUL": "Das wasswort wurde zurückgesetzt.",
"REGISTRATION_DISABLED": "Registrierung ist derzeit deaktiviert.",
"REGISTRATION_ENABLED": "Registrierung ist derzeit aktiviert.",
"RESET_USER_PASSWORD": "Passwort zurücksetzen",
"SPORTS": {
"TABLE": {
"ACTIVE": "Aktiv",
"HAS_WORKOUTS": "Trainings existieren",
"IMAGE": "Bild",
"LABEL": "Titel"
},
"TITLE": "Sportarten Administration"
},
"UPDATE_APPLICATION_DESCRIPTION": "Aktualisiere Anwemdungskonfiguration (maximale Anzahl an registrierten Nutzern, maximale Dateigröße).",
"UPDATE_USER_EMAIL": "Aktualisiere E-Mail",
"USER": "Nutzer",
"USER_EMAIL_UPDATE_SUCCESSFUL": "Die E-Mail Adresse wurde aktualisiert.",
"USERS": {
"TABLE": {
"ADD_ADMIN_RIGHTS": "Administratorrechte hinzufügen",
"REMOVE_ADMIN_RIGHTS": "Administratorrechte entfernen"
},
"SELECTS": {
"ORDER_BY": {
"ADMIN": "Adminstatus",
"CREATED_AT": "Registrierungsdatum",
"IS_ACTIVE": "Accountstatus",
"USERNAME": "Nutzername",
"WORKOUTS_COUNT": "Trainingsanzahl"
}
}
}
}

View File

@ -0,0 +1,34 @@
{
"ERROR": {
"UNKNOWN": "Fehler. Bitte versuche es erneut oder kontaktiere den Administrator.",
"email: valid email must be provided": "E-Mail: Eine gültige E-Mail muss angegeben werden.",
"error on getting configuration": "Fehler beim Abrufen der Konfiguration.",
"error when updating configuration": "Fehler beim Aktualisieren der Konfiguration.",
"error, please try again or contact the administrator": "Fehler. Bitte versuche es erneut oder kontaktiere den Administrator.",
"error, registration is disabled": "Fehler. Die Registrierung ist deaktiviert.",
"file extension not allowed": "Dateierweiterung ist nicht erlaubt.",
"file size is greater than the allowed size": "Die Datei ist größer als erlaubt.",
"invalid credentials": "Ungültige Anmeldedaten.",
"invalid payload": "Die bereitgestellten Daten sind ungültig.",
"invalid token, please log in again": "Ungültiges Token, bitte erneut anmelden.",
"invalid token, please request a new token": "Ungültiges Token, bitte erneut anmelden.",
"Network Error": "Netzwerkfehler.",
"new email must be different than curent email": "Die neue E-Mail muss sich von der aktuellen E-Mail unterscheiden.",
"no file part": "Keine Datei angegeben.",
"no selected file": "Keine Datei ausgewählt.",
"password: password and password confirmation do not match": "Passwort: Passwort und Passwortbestätigung stimmen nicht überein.",
"provide a valid auth token": "Gebe ein gültiges Authentifizierungstoken an.",
"sorry, that username is already taken": "Es tut mir leid, der Benutzername ist schon vergeben.",
"sport does not exist": "Sportart existiert nicht.",
"signature expired, please log in again": "Die Signatur ist abgelaufen. Bitte melde dich erneut an.",
"successfully registered": "Registrierung erfolgreich.",
"user does not exist": "Der Nutzer existiert nicht.",
"valid email must be provided for admin contact": "Um den Administrator zu kontaktieren, muss eine gültige E-Mail-Adresse angegeben werden.",
"you can not delete your account, no other user has admin rights": "Du kannst Dein Konto nicht löschen, da kein anderer Nutzer hat Administratorrechte besitzt.",
"you do not have permissions": "Du hast keine Berechtigung."
},
"PAGINATION": {
"PREVIOUS": "Vorhergehende",
"NEXT": "Nächste"
}
}

View File

@ -0,0 +1,17 @@
{
"ACCOUNT-CONFIRMATION-RESEND": "Bestätigungs-E-Mail erneut senden",
"BACK": "Zurück",
"CANCEL": "Abbrechen",
"CLEAR_FILTER": "Filter löschen",
"DELETE_MY_ACCOUNT": "Lösche meinen Account",
"DISABLE": "Deaktivieren",
"EDIT": "Editieren",
"ENABLE": "Aktivieren",
"FILTER": "Filter",
"LOGIN": "Einloggen",
"NO": "Nein",
"REGISTER": "Registrieren",
"RESET": "Zurücksetzen",
"SUBMIT": "Speichern",
"YES": "Ja"
}

View File

@ -0,0 +1,23 @@
{
"ABOUT": "Über",
"CONFIRMATION": "Bestätigung",
"CONTACT": "Kontakt",
"DAY": "Tag | Tage",
"DOCUMENTATION": "Dokumentation (en)",
"HOME": "Startseite",
"HERE": "hier",
"SELECTS": {
"ORDER_BY": {
"LABEL": "sortiert nach"
},
"ORDER": {
"LABEL": "sortieren",
"ASC": "aufsteigend",
"DESC": "absteigend"
},
"PER_PAGE": {
"LABEL": "pro Seite"
}
},
"TOTAL": "Insgesamt"
}

View File

@ -0,0 +1,4 @@
{
"DASHBOARD": "Dashboard",
"THIS_MONTH": "Dieser Monat"
}

View File

@ -0,0 +1,27 @@
import AboutTranslations from './about.json'
import AdministrationTranslations from './administration.json'
import ApiTranslations from './api.json'
import ButtonsTranslations from './buttons.json'
import CommonTranslations from './common.json'
import DashboardTranslations from './dashboard.json'
import ErrorTranslations from './error.json'
import OAuth2Translations from './oauth2.json'
import SportsTranslations from './sports.json'
import StatisticsTranslations from './statistics.json'
import UserTranslations from './user.json'
import WorkoutsTranslations from './workouts.json'
export default {
about: AboutTranslations,
admin: AdministrationTranslations,
api: ApiTranslations,
buttons: ButtonsTranslations,
common: CommonTranslations,
dashboard: DashboardTranslations,
error: ErrorTranslations,
oauth2: OAuth2Translations,
sports: SportsTranslations,
statistics: StatisticsTranslations,
user: UserTranslations,
workouts: WorkoutsTranslations,
}

View File

@ -0,0 +1,9 @@
{
"UNKNOWN": "Fehler. Bitte versuche es erneut oder kontaktiere den Administrator.",
"APP_ERROR": "Bei der Anwendung scheinen einige Probleme aufgetreten zu sein.<br />Bitte versuche es später noch einmal oder kontaktiere den Administrator.",
"NOT_FOUND": {
"PAGE": "Seite nicht gefunden",
"WORKOUT": "Training nicht gefunden"
},
"SOMETHING_WRONG": "Etwas lief schief"
}

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,38 @@
{
"Cycling (Sport)": {
"LABEL": "Radfahren (Sport)"
},
"Cycling (Transport)": {
"LABEL": "Radfahren (Pendeln)"
},
"Hiking": {
"LABEL": "Wandern"
},
"Mountain Biking": {
"LABEL": "Mountainbiken"
},
"Mountain Biking (Electric)": {
"LABEL": "Mountainbiken (elektrisch)"
},
"Rowing": {
"LABEL": "Rudern"
},
"Running": {
"LABEL": "Laufen"
},
"Skiing (Alpine)": {
"LABEL": "Skifahren (Alpin)"
},
"Skiing (Cross Country)": {
"LABEL": "Skifahren (Langlauf)"
},
"Snowshoes": {
"LABEL": "Schneeschuhe"
},
"Trail": {
"LABEL": "Trail"
},
"Walking": {
"LABEL": "Walking"
}
}

View File

@ -0,0 +1,8 @@
{
"STATISTICS": "Statistik",
"TIME_FRAMES": {
"week": "Woche",
"month": "Monat",
"year": "Jahr"
}
}

View File

@ -0,0 +1,108 @@
{
"ACCOUNT_CONFIRMATION_NOT_RECEIVED": "Hast du keine Anweisungen erhalten?",
"ACCOUNT_CONFIRMATION_SENT": "Prüfe Deine E-Mail. Eine neue Bestätigungsemail wurde an die angegebene Adresse geschickt.",
"ADMIN": "Admin",
"ALREADY_HAVE_ACCOUNT": "Hast du bereits ein Konto?",
"CONFIRM_ACCOUNT_DELETION": "Möchtest Du Dein Konto wirklich löschen? Alle Daten werden gelöscht. Dieser Vorgang kann nicht rückgängig gemacht werden.",
"CURRENT_PASSWORD": "Aktuelles Passwort",
"EMAIL": "E-Mail",
"EMAIL_INFO": "Gebe eine gültige E-Mail-Adresse an.",
"ENTER_PASSWORD": "Gebe ein Passwort ein",
"FILTER_ON_USERNAME": "Nach Benutzernamen filtern",
"HIDE_PASSWORD": "Passwort verbergen",
"INVALID_TOKEN": "Ungültiges Token, bitte fordere ein neues Passworts an.",
"LANGUAGE": "Sprache",
"LOG_IN": "Anmelden",
"LOGIN": "Anmeldung",
"LOGOUT": "Abmelden",
"NEW_PASSWORD": "Neues Passwort",
"NO_USERS_FOUND": "Keine Nutzer gefunden.",
"PASSWORD": "Passwort",
"PASSWORD_INFO": "Mindestens 8 Zeichen sind erforderlich.",
"PASSWORD_FORGOTTEN": "Passwort vergessen?",
"PASSWORD_RESET": "Passwort zurücksetzen",
"PASSWORD_SENT_EMAIL_TEXT": "Prüfe Deine E-Mail. Wenn Deine Adresse in der Datenbank enthalten ist, wirst du eine E-Mail mit einem Link erhalten um Dein Passwort zurückzusetzen.",
"PASSWORD_STRENGTH": {
"WEAK": "schwach",
"AVERAGE": "mittel",
"GOOD": "gut",
"STRONG": "start",
"LABEL": "Passwortstärke",
"SUGGESTIONS": {
"l33t": "Vermeide vorhersehbare Buchstabenersetzungen wie {'@'} für a.",
"reverseWords": "Vermeide umgekehrte Schreibweisen gebräuchlicher Wörter.",
"allUppercase": "Schreibe einige, aber nicht alle Buchstaben groß.",
"capitalization": "Schreibe mehr als nur den ersten Buchstaben groß.",
"dates": "Vermeide Daten und Jahreszahlen, die mit Dir in Verbindung gebracht werden.",
"recentYears": "Vermeide Angabe von letzten Jahreszahlen.",
"associatedYears": "Vermeide Jahreszahlen, die mit Dir in Verbindung gebracht werden.",
"sequences": "Vermeide gebräuchliche Zeichenfolgen.",
"repeated": "Vermeide wiederholungen von Wörtern und Zeichen.",
"longerKeyboardPattern": "Verwende längere Tastaturmuster und ändere mehrmals die Schreibrichtung.",
"anotherWord": "Füge weitere weniger gebräuchliche Wörter hinzu.",
"useWords": "Verwenden Sie mehrere Wörter, aber vermeide gebräuchliche Ausdrücke.",
"noNeed": "Du kannst sichere Passwörter erstellen, ohne Symbole, Zahlen oder Großbuchstaben zu verwenden.",
"pwned": "Wenn Sie dieses Passwort auch anderweitig verwenden, sollten Sie es ändern."
}
},
"PASSWORD_UPDATED": "Dein Passwort wurde aktualisiert. Klicke {0} um dich anzumelden.",
"PROFILE": {
"ACCOUNT_EDITION": "Kontoausgabe",
"BACK_TO_PROFILE": "Zurück zum Profil",
"BIO": "Biographie",
"BIRTH_DATE": "Geburtsdatum",
"EDIT": "Profil bearbeiten",
"EDIT_PREFERENCES": "Einstellungen ändern",
"EDIT_SPORTS_PREFERENCES": "Einstellungen für Sportarten ändern",
"ERRORED_EMAIL_UPDATE": "Bitte {0} um Deine E-Mail Adresse nochmals zu ändern oder kontaktiere den Administrator",
"FIRST_NAME": "Vorname",
"FIRST_DAY_OF_WEEK": "Erster Tag der Woche",
"LANGUAGE": "Sprache",
"LAST_NAME": "Nachname",
"LOCATION": "Ort",
"MONDAY": "Montag",
"PICTURE": "Bild",
"PICTURE_EDITION": "Bildausgabe",
"PICTURE_UPDATE": "Bild aktualisieren",
"PICTURE_REMOVE": "Bild entfernen",
"PREFERENCES_EDITION": "Einstellungsausgabe",
"PROFILE_EDITION": "Profil-Ausgabe",
"REGISTRATION_DATE": "Regirierungsdatum",
"SPORTS_EDITION": "Sportarten-Einstellungsausgabe",
"SUNDAY": "Sontag",
"TABS": {
"ACCOUNT": "Konto",
"PICTURE": "Bild",
"PREFERENCES": "Einstellungen",
"PROFILE": "Profil",
"SPORTS": "Sportarten"
},
"SPORT": {
"ACTION": "Aktion",
"COLOR": "Farbe",
"DISABLED_BY_ADMIN": "vom Admin deaktiviert",
"IS_ACTIVE": "aktiv",
"LABEL": "Titel",
"STOPPED_SPEED_THRESHOLD": "Geschwindigkeitsschwellenwert für Stopp"
},
"SUCCESSFUL_EMAIL_UPDATE": "Dein Konto wurde erfolgreich aktualisiert. Bitte prüfe Deine E-Mail um die neue E-Mail Adresse zu bestätigen.",
"SUCCESSFUL_REGISTRATION": "Dein Konto wurde erfolgreich erstellt.",
"SUCCESSFUL_REGISTRATION_WITH_EMAIL": "Ein Aktivierungslink für Dein Konto wurde an die angegebene E-Mail Adresse geschickt.",
"SUCCESSFUL_UPDATE": "Dein Konto wurde erfolgreich aktualisiert.",
"UNITS": {
"LABEL": "Einheiten für die Distanz",
"IMPERIAL": "Imperiales System (ft, mi)",
"METRIC": "Metrisches System (m, km)"
},
"TIMEZONE": "Zeitzone"
},
"REGISTER": "Registrieren",
"RESENT_ACCOUNT_CONFIRMATION": "Sende Email zur Kontobestätigung erneut",
"REGISTER_DISABLED": "Entschuldigung, die Registrierung ist deaktiviert.",
"RESET_PASSWORD": "Passwort zurücksetzen",
"SHOW_PASSWORD": "Passwort anzeigen",
"THIS_USER_ACCOUNT_IS_INACTIVE": "Dieser Account ist inaktiv.",
"USER_PICTURE": "Benutzerbild",
"USERNAME": "Nutzername",
"USERNAME_INFO": "3 bis 30 Zeichen sind erforderlich, nur alphanumerische Zeichen und der Unterstrich \"_\" sind erlaubt."
}

View File

@ -0,0 +1,101 @@
{
"ADD_WORKOUT": "Training hinzufügen",
"ANALYSIS": "Analyse",
"ASCENT": "Aufstieg",
"AVE_SPEED": "Durchschn. Geschwindigkeit",
"AVERAGE_SPEED": "Durchschnittsgeschwindigkeit",
"BACK_TO_WORKOUT": "zurück zum Training",
"DATE": "Datum",
"DESCENT": "Abstieg",
"DISPLAY_FILTERS": "zeige Filter",
"DISTANCE": "Entfernung",
"DURATION": "Dauer",
"EDIT_WORKOUT": "Training bearbeiten",
"ELEVATION": "Höhe",
"END": "Ende",
"FROM": "Von",
"GPX_FILE": ".gpx Datei",
"HIDE_FILTERS": "verberge Filter",
"LATEST_WORKOUTS": "Letzte Trainings",
"LOAD_MORE_WORKOUT": "Lade mehr Trainings",
"MAX_ALTITUDE": "maximale Höhe",
"MAX_FILES": "Maximale Dateianzahl",
"MAX_SIZE": "Maximalgröße",
"MAX_SPEED": "Max. Geschwindigkeit",
"MIN_ALTITUDE": "minimale Höhe",
"NEXT_SEGMENT": "Nächstes Segment",
"NEXT_WORKOUT": "Nächstes Training",
"NO_DATA_CLEANING": "Daten aus gpx, ohne Bereinigung",
"NO_FILE_PROVIDED": "Keine Datei angegeben",
"NO_FOLDER": "enthält keinen Ordner",
"NO_MAP": "Keine Karte",
"NO_NEXT_SEGMENT": "Kein nächstes Segment",
"NO_NEXT_WORKOUT": "Kein nächstes Training",
"NO_NOTES": "Keine Anmerkungen",
"NO_PREVIOUS_SEGMENT": "Kein vorheriges Segment",
"NO_PREVIOUS_WORKOUT": "Kein vorheriges Training",
"NO_RECORDS": "Keine Aufzeichnungen.",
"NO_WORKOUTS": "Keine Trainings.",
"NOTES": "Anmerkungen",
"PAUSES": "Pausen",
"PREVIOUS_SEGMENT": "Vorheriges Segment",
"PREVIOUS_WORKOUT": "Vorheriges Training",
"RECORD": "Aufzeichnung | Aufzeichnungen",
"RECORD_AS": "Durchschn. Geschwindigkeit",
"RECORD_FD": "Weiteste Entfernung",
"RECORD_LD": "Längste Dauer",
"RECORD_MS": "Max. Geschwindigkeit",
"REMAINING_CHARS": "remaining characters",
"SEGMENT": "Segment | Segmente",
"SPEED": "Geschwindigkeit",
"SPORT": "Sportart | Sportarten",
"START": "Start",
"START_AND_FINISH": "Start und Ziel",
"START_ELEVATION_AT_ZERO": "Höhenachse bei Null starten",
"TITLE": "Titel",
"TO": "bis",
"TOTAL_DURATION": "Gesamtdauer",
"UPLOAD_FIRST_WORKOUT": "Füge erstes Training hinzu!",
"WEATHER": {
"HUMIDITY": "Luftfeuchtigkeit",
"TEMPERATURE": "Temperatur",
"WIND": "Wind",
"WIND_DIRECTIONS": {
"N": "N",
"NNE": "NNO",
"NE": "NO",
"ENE": "ONO",
"E": "O",
"ESE": "OSO",
"SE": "SO",
"SSE": "SSO",
"S": "S",
"SSW": "SSW",
"SW": "SW",
"WSW": "WSW",
"W": "W",
"WNW": "WNW",
"NW": "NW",
"NNW": "NNW"
},
"DARK_SKY": {
"clear-day": "klarer Tag",
"clear-night": "klare Nacht",
"cloudy": "wolkig",
"fog": "Nebel",
"partly-cloudy-day": "teilweise bewölkter Tag",
"partly-cloudy-night": "teilweise bewölkte Nacht",
"rain": "Regen",
"sleet": "Schneeregen",
"snow": "Schnee",
"wind": "Wind"
}
},
"WITH_GPX": "mit .gpx Datei",
"WITHOUT_GPX": "ohne .gpx Datei",
"WORKOUT": "Training | Trainings",
"WORKOUT_DATE": "Trainingsdatum",
"WORKOUT_DELETION_CONFIRMATION": "Bist du sicher, dass du dieses Training löschen möchtest?",
"ZIP_ARCHIVE": ".zip Datei",
"ZIP_ARCHIVE_DESCRIPTION": "oder .zip Datei mit .gpx Dateien"
}

View File

@ -1,6 +1,6 @@
{
"CONTACT_ADMIN": "Contacter l'administrateur",
"FITTRACKEE_DESCRIPTION": "<strong>FitTrackee</strong> est un <em>tracker</em> d'activités sportives (en extérieur).",
"FITTRACKEE_LICENSE": "sous license {0} (en)",
"SOURCE_CODE": "Code source (en)"
}
"CONTACT_ADMIN": "Contacter l'administrateur",
"FITTRACKEE_DESCRIPTION": "<strong>FitTrackee</strong> est un <em>tracker</em> d'activités sportives (en extérieur).",
"FITTRACKEE_LICENSE": "sous licence {0} (en) ",
"SOURCE_CODE": "Code source (en)"
}

View File

@ -1,34 +1,34 @@
{
"ERROR": {
"UNKNOWN": "Erreur. Veuillez réessayer ou contacter l'administrateur.",
"email: valid email must be provided": "Email : une adresse email valide doit être fournie.",
"error on getting configuration": "Erreur lors de la récupération de la configuration.",
"error when updating configuration": "Erreur lors de la mise à jour de la configuration",
"error, please try again or contact the administrator": "Erreur, veuillez réessayer ou contacter l'administrateur.",
"error, registration is disabled": "Erreur, les inscriptions sont désactivées.",
"file extension not allowed": "Extension de fichier non autorisée.",
"file size is greater than the allowed size": "La taille du fichier est supérieure à la limite autorisée.",
"invalid credentials": "Identifiants invalides.",
"invalid payload": "Données fournies incorrectes.",
"invalid token, please log in again": "Jeton de connexion invalide, merci de vous reconnecter.",
"invalid token, please request a new token": "Jeton de connexion, merci de vous reconnecter.",
"no file part": "Pas de fichier fourni.",
"no selected file": "Pas de fichier sélectionné.",
"Network Error": "Erreur Réseau.",
"new email must be different than curent email": "La nouvelle addresse email doit être differente de l'adresse actuelle",
"password: password and password confirmation do not match": "Mot de passe : les mots de passe saisis sont différents.",
"provide a valid auth token": "Merci de fournir un jeton de connexion valide.",
"sport does not exist": "Ce sport n'existe pas.",
"signature expired, please log in again": "Signature expirée. Merci de vous reconnecter.",
"sorry, that username is already taken": "Désolé, ce nom d'utilisateur est déjà utilisé.",
"successfully registered": "Inscription validée.",
"user does not exist": "L'utilisateur n'existe pas",
"valid email must be provided for admin contact": "Une adresse email doit être fournie pour le contact de l'administrateur.",
"you can not delete your account, no other user has admin rights": "Vous ne pouvez pas supprimer votre compte, aucun autre utilisateur n'a des droits d'administration.",
"you do not have permissions": "Vous n'avez pas les permissions nécessaires."
},
"PAGINATION": {
"PREVIOUS": "précédent",
"NEXT": "suivant"
}
}
"ERROR": {
"UNKNOWN": "Erreur. Veuillez réessayer ou contacter l'administrateur.",
"email: valid email must be provided": "Courriel : une adresse électronique valide doit être fournie.",
"error on getting configuration": "Erreur lors de la récupération de la configuration.",
"error when updating configuration": "Erreur lors de la mise à jour de la configuration",
"error, please try again or contact the administrator": "Erreur, veuillez réessayer ou contacter l'administrateur.",
"error, registration is disabled": "Erreur, les inscriptions sont désactivées.",
"file extension not allowed": "Extension de fichier non autorisée.",
"file size is greater than the allowed size": "La taille du fichier est supérieure à la limite autorisée.",
"invalid credentials": "Identifiants invalides.",
"invalid payload": "Données fournies incorrectes.",
"invalid token, please log in again": "Jeton de connexion invalide, merci de vous reconnecter.",
"invalid token, please request a new token": "Jeton de connexion, merci de vous reconnecter.",
"no file part": "Pas de fichier fourni.",
"no selected file": "Pas de fichier sélectionné.",
"Network Error": "Erreur réseau.",
"new email must be different than curent email": "La nouvelle addresse électronique doit être differente de l'adresse actuelle",
"password: password and password confirmation do not match": "Mot de passe : les mots de passe saisis sont différents.",
"provide a valid auth token": "Merci de fournir un jeton de connexion valide.",
"sport does not exist": "Ce sport n'existe pas.",
"signature expired, please log in again": "Signature expirée. Merci de vous reconnecter.",
"sorry, that username is already taken": "Désolé, ce nom d'utilisateur est déjà utilisé.",
"successfully registered": "Inscription validée.",
"user does not exist": "L'utilisateur n'existe pas.",
"valid email must be provided for admin contact": "Une adresse électronique doit être fournie pour le contact de l'administrateur",
"you can not delete your account, no other user has admin rights": "Vous ne pouvez pas supprimer votre compte, aucun autre utilisateur n'a des droits d'administration.",
"you do not have permissions": "Vous n'avez pas les permissions nécessaires."
},
"PAGINATION": {
"PREVIOUS": "précédent",
"NEXT": "suivant"
}
}

View File

@ -1,18 +1,17 @@
{
"ACCOUNT-CONFIRMATION-RESEND": "Envoyer à nouveau l'email de confirmation",
"AUTHORIZE": "Autoriser",
"BACK": "Précédent",
"CANCEL": "Annuler",
"CLEAR_FILTER": "Réinitialiser",
"DELETE_MY_ACCOUNT": "Supprimer mon compte",
"DISABLE": "Désactiver",
"EDIT": "Modifier",
"ENABLE": "Activer",
"FILTER": "Filtrer",
"LOGIN": "Se connecter",
"NO": "Non",
"REGISTER": "S'inscrire",
"RESET": "Réinit.",
"SUBMIT": "Valider",
"YES": "Oui"
}
"ACCOUNT-CONFIRMATION-RESEND": "Renvoyer le message de confirmation",
"AUTHORIZE": "Autoriser",
"CANCEL": "Annuler",
"CLEAR_FILTER": "Réinitialiser",
"DELETE_MY_ACCOUNT": "Supprimer mon compte",
"DISABLE": "Désactiver",
"EDIT": "Modifier",
"ENABLE": "Activer",
"FILTER": "Filtrer",
"LOGIN": "Se connecter",
"NO": "Non",
"REGISTER": "S'inscrire",
"RESET": "Réinit.",
"SUBMIT": "Valider",
"YES": "Oui"
}

View File

@ -1,4 +1,4 @@
{
"DASHBOARD": "Tableau de Bord",
"THIS_MONTH": "Ce mois"
"DASHBOARD": "Tableau de bord",
"THIS_MONTH": "Ce mois-ci"
}

View File

@ -1,38 +1,38 @@
{
"Cycling (Sport)": {
"LABEL": "Vélo (Sport)"
},
"Cycling (Transport)": {
"LABEL": "Vélo (Transport)"
},
"Hiking": {
"LABEL": "Randonnée"
},
"Mountain Biking": {
"LABEL": "VTT"
},
"Mountain Biking (Electric)": {
"LABEL": "VTT (Electrique)"
},
"Rowing": {
"LABEL": "Aviron"
},
"Running": {
"LABEL": "Course"
},
"Skiing (Alpine)": {
"LABEL": "Ski (Alpin)"
},
"Skiing (Cross Country)": {
"LABEL": "Ski (Randonnée)"
},
"Snowshoes": {
"LABEL": "Raquettes"
},
"Trail": {
"LABEL": "Trail"
},
"Walking": {
"LABEL": "Marche"
}
}
"Cycling (Sport)": {
"LABEL": "Vélo (Sport)"
},
"Cycling (Transport)": {
"LABEL": "Vélo (Transport)"
},
"Hiking": {
"LABEL": "Randonnée"
},
"Mountain Biking": {
"LABEL": "VTT"
},
"Mountain Biking (Electric)": {
"LABEL": "VTT (Électrique)"
},
"Rowing": {
"LABEL": "Aviron"
},
"Running": {
"LABEL": "Course"
},
"Skiing (Alpine)": {
"LABEL": "Ski (Alpin)"
},
"Skiing (Cross Country)": {
"LABEL": "Ski (Randonnée)"
},
"Snowshoes": {
"LABEL": "Raquettes"
},
"Trail": {
"LABEL": "Trail"
},
"Walking": {
"LABEL": "Marche"
}
}

View File

@ -1,109 +1,109 @@
{
"ACCOUNT_CONFIRMATION_NOT_RECEIVED": "Vous n'avez pas reçu les instructions ?",
"ACCOUNT_CONFIRMATION_SENT": "Vérifiez votre boite mail. Un nouvel email de confirmation a été envoyé à l'adresse email fournie.",
"ADMIN": "Admin",
"ALREADY_HAVE_ACCOUNT": "Vous avez déjà un compte ?",
"CONFIRM_ACCOUNT_DELETION": "Êtes-vous sûr de vouloir supprimer votre compte ? Toutes les données seront définitivement effacés.",
"CURRENT_PASSWORD": "Mot de passe actuel",
"EMAIL": "Email",
"EMAIL_INFO": "Saisir une adresse email valide.",
"ENTER_PASSWORD": "Saisir un mot de passe",
"FILTER_ON_USERNAME": "Filtrer sur le nom d'utilisateur",
"HIDE_PASSWORD": "masquer le mot de passe",
"INVALID_TOKEN": "Jeton invalide, veuillez demander une nouvelle réinitialisation de mot de passe.",
"LANGUAGE": "Langue",
"LOG_IN": "connecter",
"LOGIN": "Se connecter",
"LOGOUT": "Se déconnecter",
"NEW_PASSWORD": "Nouveau mot de passe",
"NO_USERS_FOUND": "Aucun utilisateur trouvé.",
"PASSWORD": "Mot de passe",
"PASSWORD_INFO": "8 caractères minimum.",
"PASSWORD_FORGOTTEN": "Mot de passe oublié ?",
"PASSWORD_RESET": "Réinitialisation du mot de passe",
"PASSWORD_SENT_EMAIL_TEXT": "Vérifiez votre boite mail. Si vote adresse est dans notre base de données, vous recevrez un email avec un lien pour réinitialiser votre mot de passe.",
"PASSWORD_STRENGTH": {
"WEAK": "faible",
"AVERAGE": "moyenne",
"GOOD": "bonne",
"STRONG": "forte",
"LABEL": "robustesse du mot de passe ",
"SUGGESTIONS": {
"l33t": "Évitez les substitutions de lettres prévisibles comme {'@'} pour a.",
"reverseWords": "Évitez les orthographes inversées des mots courants",
"allUppercase": "Mettez quelques lettres en majuscules, mais pas toutes.",
"capitalization": "Capitalisez mais pas seulement la première lettre.",
"dates": "Évitez les dates et les années qui vous sont associées. (ex: date ou année de naissance)",
"recentYears": "Évitez les dernières années.",
"associatedYears": "Évitez les années qui vous sont associées. (ex: date de naissance)",
"sequences": "Évitez les séquences de caractères courantes.",
"repeated": "Évitez les mots et les caractères répétés.",
"longerKeyboardPattern": "Utilisez des motifs de clavier plus longs et changez de sens de frappe plusieurs fois.",
"anotherWord": "Ajoutez des mots moins courants.",
"useWords": "Utilisez plusieurs mots, mais évitez les phrases courantes.",
"noNeed": "Vous pouvez créer des mots de passe forts sans utiliser de symboles, de chiffres ou de lettres majuscules.",
"pwned": "Si vous utilisez ce mot de passe ailleurs, vous devriez le modifier."
}
},
"PASSWORD_UPDATED": "Votre mot de passe a été mis à jour. Cliquez {0} pour vous connecter.",
"PROFILE": {
"ACCOUNT_EDITION": "Mise à jour du compte",
"BACK_TO_PROFILE": "Revenir au profil",
"BIO": "Bio",
"BIRTH_DATE": "Date de naissance",
"EDIT": "Modifier le profil",
"EDIT_PREFERENCES": "Modifier les préférences",
"EDIT_SPORTS_PREFERENCES": "Modifier les préférences des sports",
"ERRORED_EMAIL_UPDATE": "Veuillez vous {0} pour changer de nouveau votre adresse email ou contacter l'administrateur",
"FIRST_DAY_OF_WEEK": "Premier jour de la semaine",
"FIRST_NAME": "Prénom",
"ACCOUNT_CONFIRMATION_NOT_RECEIVED": "Vous n'avez pas reçu les instructions ?",
"ACCOUNT_CONFIRMATION_SENT": "Vérifiez votre boite mail. Un nouvel email de confirmation a été envoyé à l'adresse email fournie.",
"ADMIN": "Admin",
"ALREADY_HAVE_ACCOUNT": "Vous avez déjà un compte ?",
"CONFIRM_ACCOUNT_DELETION": "Êtes-vous sûr de vouloir supprimer votre compte ? Toutes les données seront définitivement effacés.",
"CURRENT_PASSWORD": "Mot de passe actuel",
"EMAIL": "Email",
"EMAIL_INFO": "Saisir une adresse email valide.",
"ENTER_PASSWORD": "Saisir un mot de passe",
"FILTER_ON_USERNAME": "Filtrer sur le nom d'utilisateur",
"HIDE_PASSWORD": "masquer le mot de passe",
"INVALID_TOKEN": "Jeton invalide, veuillez demander une nouvelle réinitialisation de mot de passe.",
"LANGUAGE": "Langue",
"LAST_NAME": "Nom",
"LOCATION": "Lieu",
"MONDAY": "Lundi",
"PICTURE": "Image de profil",
"PICTURE_EDITION": "Mise à jour de l'image de profil",
"PICTURE_UPDATE": "Mettre à jour l'image",
"PICTURE_REMOVE": "Supprimer",
"PREFERENCES_EDITION": "Mise à jour des préférences",
"PROFILE_EDITION": "Mise à jour du profil",
"REGISTRATION_DATE": "Date d'inscription",
"SPORTS_EDITION": "Mise à jour des préférences des sports",
"SUNDAY": "Dimanche",
"TABS": {
"ACCOUNT": "compte",
"APPS": "apps",
"PICTURE": "image",
"PREFERENCES": "préférences",
"PROFILE": "profil",
"SPORTS": "sports"
"LOG_IN": "connecter",
"LOGIN": "Se connecter",
"LOGOUT": "Se déconnecter",
"NEW_PASSWORD": "Nouveau mot de passe",
"NO_USERS_FOUND": "Aucun utilisateur trouvé.",
"PASSWORD": "Mot de passe",
"PASSWORD_INFO": "8 caractères minimum.",
"PASSWORD_FORGOTTEN": "Mot de passe oublié ?",
"PASSWORD_RESET": "Réinitialisation du mot de passe",
"PASSWORD_SENT_EMAIL_TEXT": "Vérifiez votre boite mail. Si vote adresse est dans notre base de données, vous recevrez un email avec un lien pour réinitialiser votre mot de passe.",
"PASSWORD_STRENGTH": {
"WEAK": "faible",
"AVERAGE": "moyenne",
"GOOD": "bonne",
"STRONG": "forte",
"LABEL": "robustesse du mot de passe ",
"SUGGESTIONS": {
"l33t": "Évitez les substitutions de lettres prévisibles comme {'@'} pour a.",
"reverseWords": "Évitez les orthographes inversées des mots courants.",
"allUppercase": "Mettez quelques lettres en majuscules, mais pas toutes.",
"capitalization": "Capitalisez mais pas seulement la première lettre.",
"dates": "Évitez les dates et les années qui vous sont associées. (ex : date ou année de naissance).",
"recentYears": "Évitez les dernières années.",
"associatedYears": "Évitez les années qui vous sont associées. (ex : date de naissance).",
"sequences": "Évitez les séquences de caractères courantes.",
"repeated": "Évitez les mots et les caractères répétés.",
"longerKeyboardPattern": "Utilisez des motifs de clavier plus longs et changez de sens de frappe plusieurs fois.",
"anotherWord": "Ajoutez des mots moins courants.",
"useWords": "Utilisez plusieurs mots, mais évitez les phrases courantes.",
"noNeed": "Vous pouvez créer des mots de passe forts sans utiliser de symboles, de chiffres ou de lettres majuscules.",
"pwned": "Si vous utilisez ce mot de passe ailleurs, vous devriez le modifier."
}
},
"UNITS": {
"LABEL": "Unités pour les distances ",
"IMPERIAL": "Système impérial (ft, mi)",
"METRIC": "Système métrique (m, km)"
"PASSWORD_UPDATED": "Votre mot de passe a été mis à jour. Cliquez {0} pour vous connecter.",
"PROFILE": {
"ACCOUNT_EDITION": "Mise à jour du compte",
"BACK_TO_PROFILE": "Revenir au profil",
"BIO": "Bio",
"BIRTH_DATE": "Date de naissance",
"EDIT": "Modifier le profil",
"EDIT_PREFERENCES": "Modifier les préférences",
"EDIT_SPORTS_PREFERENCES": "Modifier les préférences des sports",
"ERRORED_EMAIL_UPDATE": "Veuillez vous {0} pour changer de nouveau votre adresse email ou contacter l'administrateur",
"FIRST_DAY_OF_WEEK": "Premier jour de la semaine",
"FIRST_NAME": "Prénom",
"LANGUAGE": "Langue",
"LAST_NAME": "Nom",
"LOCATION": "Lieu",
"MONDAY": "Lundi",
"PICTURE": "Image de profil",
"PICTURE_EDITION": "Mise à jour de l'image de profil",
"PICTURE_UPDATE": "Mettre à jour l'image",
"PICTURE_REMOVE": "Supprimer",
"PREFERENCES_EDITION": "Mise à jour des préférences",
"PROFILE_EDITION": "Mise à jour du profil",
"REGISTRATION_DATE": "Date d'inscription",
"SPORTS_EDITION": "Mise à jour des préférences des sports",
"SUNDAY": "Dimanche",
"TABS": {
"ACCOUNT": "compte",
"APPS": "apps",
"PICTURE": "image",
"PREFERENCES": "préférences",
"PROFILE": "profil",
"SPORTS": "sports"
},
"UNITS": {
"LABEL": "Unités pour les distances ",
"IMPERIAL": "Système impérial (ft, mi)",
"METRIC": "Système métrique (m, km)"
},
"SPORT": {
"ACTION": "action",
"COLOR": "couleur",
"DISABLED_BY_ADMIN": "désactivé par l'administrateur",
"IS_ACTIVE": "actif",
"LABEL": "label",
"STOPPED_SPEED_THRESHOLD": "seuil de vitesse arrêtée"
},
"SUCCESSFUL_EMAIL_UPDATE": "Votre compte a été modifié avec succès. Veuillez vérifier votre boite email pour valider votre nouvelle adresse email.",
"SUCCESSFUL_REGISTRATION": "Votre compte a été créé avec succès.",
"SUCCESSFUL_REGISTRATION_WITH_EMAIL": "Un lien pour activer votre compte a été envoyé à l'adresse email fournie.",
"SUCCESSFUL_UPDATE": "Votre compte a été modifié avec succès.",
"TIMEZONE": "Fuseau horaire"
},
"SPORT": {
"ACTION": "action",
"COLOR": "couleur",
"DISABLED_BY_ADMIN": "désactivé par l'administrateur",
"IS_ACTIVE": "actif",
"LABEL": "label",
"STOPPED_SPEED_THRESHOLD": "seuil de vitesse arrêtée"
},
"SUCCESSFUL_EMAIL_UPDATE": "Votre compte a été modifié avec succès. Veuillez vérifier votre boite email pour valider votre nouvelle adresse email.",
"SUCCESSFUL_REGISTRATION": "Votre compte a été créé avec succès.",
"SUCCESSFUL_REGISTRATION_WITH_EMAIL": "Un lien pour activer votre compte a été envoyé à l'adresse email fournie.",
"SUCCESSFUL_UPDATE": "Votre compte a été modifié avec succès.",
"TIMEZONE": "Fuseau horaire"
},
"REGISTER": "S'inscrire",
"REGISTER_DISABLED": "Désolé, les inscriptions sont désactivées.",
"RESENT_ACCOUNT_CONFIRMATION": "Envoyer à nouveau l'email de confirmation de compte",
"RESET_PASSWORD": "Réinitialiser votre mot de passe",
"SHOW_PASSWORD": "afficher le mot de passe",
"THIS_USER_ACCOUNT_IS_INACTIVE": "Le compte de cet utilisateur est inactif.",
"USER_PICTURE": "photo de l'utilisateur",
"USERNAME": "Nom d'utilisateur",
"USERNAME_INFO": "3 à 30 caractères requis, seuls les caractères alphanumériques et le caractère \"_\" sont autorisés."
"REGISTER": "S'inscrire",
"REGISTER_DISABLED": "Désolé, les inscriptions sont désactivées.",
"RESENT_ACCOUNT_CONFIRMATION": "Envoyer à nouveau l'email de confirmation de compte",
"RESET_PASSWORD": "Réinitialiser votre mot de passe",
"SHOW_PASSWORD": "afficher le mot de passe",
"THIS_USER_ACCOUNT_IS_INACTIVE": "Le compte de cet utilisateur est inactif.",
"USER_PICTURE": "photo de l'utilisateur",
"USERNAME": "Nom d'utilisateur",
"USERNAME_INFO": "3 à 30 caractères requis, seuls les caractères alphanumériques et le caractère \"_\" sont autorisés."
}

View File

@ -2,7 +2,6 @@ import { ActionContext, ActionTree } from 'vuex'
import authApi from '@/api/authApi'
import api from '@/api/defaultApi'
import createI18n from '@/i18n'
import router from '@/router'
import {
AUTH_USER_STORE,
@ -32,8 +31,6 @@ import {
} from '@/types/user'
import { handleError } from '@/utils'
const { locale } = createI18n.global
const removeAuthUserData = (
context: ActionContext<IAuthUserState, IRootState>
) => {
@ -126,11 +123,10 @@ export const actions: ActionTree<IAuthUserState, IRootState> &
res.data.data
)
if (res.data.data.language) {
context.commit(
ROOT_STORE.MUTATIONS.UPDATE_LANG,
context.dispatch(
ROOT_STORE.ACTIONS.UPDATE_APPLICATION_LANGUAGE,
res.data.data.language
)
locale.value = res.data.data.language
}
context.dispatch(SPORTS_STORE.ACTIONS.GET_SPORTS)
} else {
@ -251,12 +247,12 @@ export const actions: ActionTree<IAuthUserState, IRootState> &
AUTH_USER_STORE.MUTATIONS.UPDATE_AUTH_USER_PROFILE,
res.data.data
)
context.commit(
ROOT_STORE.MUTATIONS.UPDATE_LANG,
res.data.data.language
)
locale.value = res.data.data.language
router.push('/profile/preferences')
context
.dispatch(
ROOT_STORE.ACTIONS.UPDATE_APPLICATION_LANGUAGE,
res.data.data.language
)
.then(() => router.push('/profile/preferences'))
} else {
handleError(context, null)
}

View File

@ -1,12 +1,15 @@
import { ActionContext, ActionTree } from 'vuex'
import authApi from '@/api/authApi'
import createI18n from '@/i18n'
import router from '@/router'
import { ROOT_STORE } from '@/store/constants'
import { IRootActions, IRootState } from '@/store/modules/root/types'
import { TAppConfigForm } from '@/types/application'
import { handleError } from '@/utils'
const { locale } = createI18n.global
export const actions: ActionTree<IRootState, IRootState> & IRootActions = {
[ROOT_STORE.ACTIONS.GET_APPLICATION_CONFIG](
context: ActionContext<IRootState, IRootState>
@ -68,4 +71,12 @@ export const actions: ActionTree<IRootState, IRootState> & IRootActions = {
})
.catch((error) => handleError(context, error))
},
[ROOT_STORE.ACTIONS.UPDATE_APPLICATION_LANGUAGE](
context: ActionContext<IRootState, IRootState>,
language: string
): void {
document.querySelector('html')?.setAttribute('lang', language)
context.commit(ROOT_STORE.MUTATIONS.UPDATE_LANG, language)
locale.value = language
},
}

View File

@ -2,6 +2,7 @@ export enum RootActions {
GET_APPLICATION_CONFIG = 'GET_APPLICATION_CONFIG',
GET_APPLICATION_STATS = 'GET_APPLICATION_STATS',
UPDATE_APPLICATION_CONFIG = 'UPDATE_APPLICATION_CONFIG',
UPDATE_APPLICATION_LANGUAGE = 'UPDATE_APPLICATION_LANGUAGE',
}
export enum RootGetters {

View File

@ -34,6 +34,10 @@ export interface IRootActions {
context: ActionContext<IRootState, IRootState>,
payload: TAppConfigForm
): void
[ROOT_STORE.ACTIONS.UPDATE_APPLICATION_LANGUAGE](
context: ActionContext<IRootState, IRootState>,
langauge: string
): void
}
export interface IRootGetters {

View File

@ -93,6 +93,7 @@ export interface ILoginRegisterFormData {
username: string
email: string
password: string
language?: string
}
export interface ILoginOrRegisterData {

View File

@ -16,6 +16,13 @@ export interface IWorkoutSegment {
workout_id: string
}
export interface ICardRecord {
id: number
value: number | string
workout_date: string
workout_id: string
label: string
}
export interface IRecord {
id: number
record_type: string

View File

@ -1,15 +1,17 @@
/* eslint-disable import/no-duplicates */
import { Locale } from 'date-fns'
import { enUS, fr } from 'date-fns/locale'
import { de, enUS, fr } from 'date-fns/locale'
import createI18n from '@/i18n'
export const localeFromLanguage: Record<string, Locale> = {
de: de,
en: enUS,
fr: fr,
}
export const languageLabels: Record<string, string> = {
de: 'Deutsch',
en: 'English',
fr: 'Français',
}

View File

@ -1,6 +1,6 @@
import { ITranslatedSport } from '@/types/sports'
import { TUnit } from '@/types/units'
import { IRecord, IRecordsBySports } from '@/types/workouts'
import { ICardRecord, IRecord, IRecordsBySports } from '@/types/workouts'
import { formatWorkoutDate, getDateWithTZ } from '@/utils/dates'
import { convertDistance, units } from '@/utils/units'
@ -45,6 +45,12 @@ export const formatRecord = (
}
}
export const sortRecords = (a: ICardRecord, b: ICardRecord): number => {
const recordALabel = a.label.toLowerCase()
const recordBLabel = b.label.toLowerCase()
return recordALabel > recordBLabel ? 1 : recordALabel < recordBLabel ? -1 : 0
}
export const getRecordsBySports = (
records: IRecord[],
translatedSports: ITranslatedSport[],

File diff suppressed because it is too large Load Diff