Merge pull request #481 from SamR1/improve-dropdowns
Handle keyboard navigation on dropdowns
This commit is contained in:
Vendored
+2
-2
@@ -7,11 +7,11 @@
|
|||||||
<link rel="stylesheet" href="/static/css/fork-awesome.min.css"/>
|
<link rel="stylesheet" href="/static/css/fork-awesome.min.css"/>
|
||||||
<link rel="stylesheet" href="/static/css/leaflet.css"/>
|
<link rel="stylesheet" href="/static/css/leaflet.css"/>
|
||||||
<title>FitTrackee</title>
|
<title>FitTrackee</title>
|
||||||
<script type="module" crossorigin src="/static/index-omYyfw-i.js"></script>
|
<script type="module" crossorigin src="/static/index-GyLsc4kt.js"></script>
|
||||||
<link rel="modulepreload" crossorigin href="/static/charts-_RwsDDkL.js">
|
<link rel="modulepreload" crossorigin href="/static/charts-_RwsDDkL.js">
|
||||||
<link rel="modulepreload" crossorigin href="/static/maps-ZyuCPqes.js">
|
<link rel="modulepreload" crossorigin href="/static/maps-ZyuCPqes.js">
|
||||||
<link rel="stylesheet" crossorigin href="/static/css/maps-B7qTrBCW.css">
|
<link rel="stylesheet" crossorigin href="/static/css/maps-B7qTrBCW.css">
|
||||||
<link rel="stylesheet" crossorigin href="/static/css/index-sAkBlxb8.css">
|
<link rel="stylesheet" crossorigin href="/static/css/index-PPVfBuiJ.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+58
-58
File diff suppressed because one or more lines are too long
@@ -1,23 +1,37 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="dropdown-wrapper">
|
<div class="dropdown-wrapper">
|
||||||
<button
|
<button
|
||||||
:aria-label="buttonLabel"
|
aria-controls="dropdown-list"
|
||||||
:aria-expanded="isOpen"
|
:aria-expanded="isOpen"
|
||||||
|
aria-haspopup="true"
|
||||||
|
:aria-label="buttonLabel"
|
||||||
class="dropdown-selector transparent"
|
class="dropdown-selector transparent"
|
||||||
@click="toggleDropdown"
|
@click="toggleDropdown()"
|
||||||
|
ref="dropdownButton"
|
||||||
>
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-list" v-if="isOpen">
|
<ul
|
||||||
|
v-if="isOpen"
|
||||||
|
:aria-labelledby="listLabel"
|
||||||
|
class="dropdown-list"
|
||||||
|
id="dropdown-list"
|
||||||
|
role="menu"
|
||||||
|
>
|
||||||
<li
|
<li
|
||||||
class="dropdown-item"
|
class="dropdown-item"
|
||||||
:class="{ selected: option.value === selected }"
|
:class="{
|
||||||
v-for="(option, index) in dropdownOptions"
|
selected: option.value === selected,
|
||||||
|
focused: index === focusOptionIndex,
|
||||||
|
}"
|
||||||
|
v-for="(option, index) in options"
|
||||||
:key="index"
|
:key="index"
|
||||||
tabindex="0"
|
:id="`dropdown-item-${index}`"
|
||||||
|
tabindex="-1"
|
||||||
@click="updateSelected(option)"
|
@click="updateSelected(option)"
|
||||||
@keydown.enter="updateSelected(option)"
|
@keydown.enter="updateSelected(option)"
|
||||||
role="button"
|
@mouseover="onMouseOver(index)"
|
||||||
|
role="menuitem"
|
||||||
>
|
>
|
||||||
{{ option.label }}
|
{{ option.label }}
|
||||||
</li>
|
</li>
|
||||||
@@ -26,7 +40,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, toRefs, watch } from 'vue'
|
import { type Ref, ref, onMounted, onUnmounted, toRefs, watch } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
import type { IDropdownOption, TDropdownOptions } from '@/types/forms'
|
import type { IDropdownOption, TDropdownOptions } from '@/types/forms'
|
||||||
@@ -34,9 +48,10 @@
|
|||||||
options: TDropdownOptions
|
options: TDropdownOptions
|
||||||
selected: string
|
selected: string
|
||||||
buttonLabel: string
|
buttonLabel: string
|
||||||
|
listLabel: string
|
||||||
}
|
}
|
||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
const { options } = toRefs(props)
|
const { options, selected } = toRefs(props)
|
||||||
|
|
||||||
const emit = defineEmits({
|
const emit = defineEmits({
|
||||||
selected: (option: IDropdownOption) => option,
|
selected: (option: IDropdownOption) => option,
|
||||||
@@ -44,20 +59,93 @@
|
|||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const isOpen = ref(false)
|
const isOpen = ref(false)
|
||||||
const dropdownOptions = options.value.map((option) => option)
|
const dropdownButton: Ref<HTMLButtonElement | null> = ref(null)
|
||||||
|
const focusOptionIndex: Ref<number> = ref(
|
||||||
|
getIndexFromOptionValue(selected.value)
|
||||||
|
)
|
||||||
|
|
||||||
function toggleDropdown() {
|
function toggleDropdown() {
|
||||||
isOpen.value = !isOpen.value
|
if (isOpen.value) {
|
||||||
|
closeDropdown()
|
||||||
|
} else {
|
||||||
|
isOpen.value = true
|
||||||
|
const option = document.getElementById(
|
||||||
|
`dropdown-item-${focusOptionIndex.value}`
|
||||||
|
)
|
||||||
|
option?.focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function closeDropdown() {
|
||||||
|
isOpen.value = false
|
||||||
|
focusOptionIndex.value = getIndexFromOptionValue(selected.value)
|
||||||
|
dropdownButton.value?.focus()
|
||||||
}
|
}
|
||||||
function updateSelected(option: IDropdownOption) {
|
function updateSelected(option: IDropdownOption) {
|
||||||
emit('selected', option)
|
emit('selected', option)
|
||||||
isOpen.value = false
|
isOpen.value = false
|
||||||
}
|
}
|
||||||
|
function getIndexFromOptionValue(value: string) {
|
||||||
|
const index = options.value.findIndex((o) => o.value === value)
|
||||||
|
return index >= 0 ? index : 0
|
||||||
|
}
|
||||||
|
function handleKey(e: KeyboardEvent) {
|
||||||
|
let prevent = false
|
||||||
|
if (isOpen.value) {
|
||||||
|
if (e.key === 'ArrowDown') {
|
||||||
|
prevent = true
|
||||||
|
focusOptionIndex.value += 1
|
||||||
|
if (focusOptionIndex.value > options.value.length) {
|
||||||
|
focusOptionIndex.value = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (e.key === 'ArrowUp') {
|
||||||
|
prevent = true
|
||||||
|
focusOptionIndex.value -= 1
|
||||||
|
if (focusOptionIndex.value < 0) {
|
||||||
|
focusOptionIndex.value = options.value.length - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (e.key === 'Home') {
|
||||||
|
prevent = true
|
||||||
|
focusOptionIndex.value = 0
|
||||||
|
}
|
||||||
|
if (e.key === 'End') {
|
||||||
|
prevent = true
|
||||||
|
focusOptionIndex.value = options.value.length - 1
|
||||||
|
}
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
prevent = true
|
||||||
|
updateSelected(options.value[focusOptionIndex.value])
|
||||||
|
}
|
||||||
|
if (e.key === 'Escape' || e.key === 'Tab') {
|
||||||
|
prevent = e.key === 'Escape'
|
||||||
|
closeDropdown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (prevent) {
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function onMouseOver(index: number) {
|
||||||
|
focusOptionIndex.value = index
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => route.path,
|
() => route.path,
|
||||||
() => (isOpen.value = false)
|
() => (isOpen.value = false)
|
||||||
)
|
)
|
||||||
|
watch(
|
||||||
|
() => selected.value,
|
||||||
|
(value) => (focusOptionIndex.value = getIndexFromOptionValue(value))
|
||||||
|
)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
document.addEventListener('keydown', handleKey)
|
||||||
|
})
|
||||||
|
onUnmounted(() => {
|
||||||
|
document.removeEventListener('keydown', handleKey)
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@@ -90,7 +178,8 @@
|
|||||||
content: ' ✔';
|
content: ' ✔';
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover,
|
||||||
|
&.focused {
|
||||||
background-color: var(--dropdown-hover-color);
|
background-color: var(--dropdown-hover-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,8 +106,9 @@
|
|||||||
:selected="language"
|
:selected="language"
|
||||||
@selected="updateLanguage"
|
@selected="updateLanguage"
|
||||||
:buttonLabel="$t('user.LANGUAGE')"
|
:buttonLabel="$t('user.LANGUAGE')"
|
||||||
|
:listLabel="$t('user.LANGUAGE', 0)"
|
||||||
>
|
>
|
||||||
<i class="fa fa-language"></i>
|
<i class="fa fa-language" aria-hidden="true"></i>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,19 +7,35 @@
|
|||||||
:value="timezone"
|
:value="timezone"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
required
|
required
|
||||||
@keydown.esc="onUpdateTimezone(input)"
|
role="combobox"
|
||||||
|
aria-autocomplete="list"
|
||||||
|
aria-controls="tz-dropdown-list"
|
||||||
|
:aria-expanded="isOpen"
|
||||||
|
@keydown.esc="cancelUpdate()"
|
||||||
@keydown.enter="onEnter"
|
@keydown.enter="onEnter"
|
||||||
@input="openDropdown"
|
@input="openDropdown"
|
||||||
|
@blur="closeDropdown()"
|
||||||
|
@keydown.down="onKeyDown()"
|
||||||
|
@keydown.up="onKeyUp()"
|
||||||
/>
|
/>
|
||||||
<ul class="tz-dropdown-list" v-if="isOpen" ref="tzList">
|
<ul
|
||||||
|
class="tz-dropdown-list"
|
||||||
|
id="tz-dropdown-list"
|
||||||
|
v-if="isOpen"
|
||||||
|
role="listbox"
|
||||||
|
tabindex="-1"
|
||||||
|
:aria-label="$t('user.PROFILE.TIMEZONE', 0)"
|
||||||
|
>
|
||||||
<li
|
<li
|
||||||
v-for="(tz, index) in timeZones.filter((t) => matchTimezone(t))"
|
v-for="(tz, index) in filteredTimezones"
|
||||||
:key="tz"
|
:key="tz"
|
||||||
|
:id="`tz-dropdown-item-${index}`"
|
||||||
class="tz-dropdown-item"
|
class="tz-dropdown-item"
|
||||||
:class="{ focus: index === focusItemIndex }"
|
:class="{ focus: index === focusItemIndex }"
|
||||||
@click="onUpdateTimezone(tz)"
|
@click="onUpdateTimezone(index)"
|
||||||
@mouseover="onMouseOver(index)"
|
@mouseover="onMouseOver(index)"
|
||||||
:autofocus="index === focusItemIndex"
|
:autofocus="index === focusItemIndex"
|
||||||
|
role="option"
|
||||||
>
|
>
|
||||||
{{ tz }}
|
{{ tz }}
|
||||||
</li>
|
</li>
|
||||||
@@ -28,8 +44,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, toRefs, watch } from 'vue'
|
import { computed, ref, toRefs, watch } from 'vue'
|
||||||
import type { Ref } from 'vue'
|
import type { ComputedRef, Ref } from 'vue'
|
||||||
|
|
||||||
import { timeZones } from '@/utils/timezone'
|
import { timeZones } from '@/utils/timezone'
|
||||||
|
|
||||||
@@ -46,8 +62,10 @@
|
|||||||
const { input, disabled } = toRefs(props)
|
const { input, disabled } = toRefs(props)
|
||||||
const timezone: Ref<string> = ref(input.value)
|
const timezone: Ref<string> = ref(input.value)
|
||||||
const isOpen: Ref<boolean> = ref(false)
|
const isOpen: Ref<boolean> = ref(false)
|
||||||
const tzList: Ref<HTMLInputElement | null> = ref(null)
|
|
||||||
const focusItemIndex: Ref<number> = ref(0)
|
const focusItemIndex: Ref<number> = ref(0)
|
||||||
|
const filteredTimezones: ComputedRef<string[]> = computed(() =>
|
||||||
|
input.value ? timeZones.filter((t) => matchTimezone(t)) : timeZones
|
||||||
|
)
|
||||||
|
|
||||||
function matchTimezone(t: string): RegExpMatchArray | null {
|
function matchTimezone(t: string): RegExpMatchArray | null {
|
||||||
return t.toLowerCase().match(timezone.value.toLowerCase())
|
return t.toLowerCase().match(timezone.value.toLowerCase())
|
||||||
@@ -55,15 +73,17 @@
|
|||||||
function onMouseOver(index: number) {
|
function onMouseOver(index: number) {
|
||||||
focusItemIndex.value = index
|
focusItemIndex.value = index
|
||||||
}
|
}
|
||||||
function onUpdateTimezone(value: string) {
|
function onUpdateTimezone(index: number) {
|
||||||
timezone.value = value
|
if (filteredTimezones.value.length > index) {
|
||||||
isOpen.value = false
|
timezone.value = filteredTimezones.value[index]
|
||||||
emit('updateTimezone', value)
|
emit('updateTimezone', timezone.value)
|
||||||
|
isOpen.value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function onEnter(event: Event) {
|
function onEnter(event: Event) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
if (tzList.value?.firstElementChild?.innerHTML) {
|
if (filteredTimezones.value.length > 0) {
|
||||||
onUpdateTimezone(tzList.value?.firstElementChild?.innerHTML)
|
onUpdateTimezone(focusItemIndex.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function openDropdown(event: Event) {
|
function openDropdown(event: Event) {
|
||||||
@@ -71,6 +91,42 @@
|
|||||||
isOpen.value = true
|
isOpen.value = true
|
||||||
timezone.value = (event.target as HTMLInputElement).value.trim()
|
timezone.value = (event.target as HTMLInputElement).value.trim()
|
||||||
}
|
}
|
||||||
|
function closeDropdown() {
|
||||||
|
onUpdateTimezone(focusItemIndex.value)
|
||||||
|
}
|
||||||
|
function scrollIntoOption(index: number) {
|
||||||
|
const option = document.getElementById(`tz-dropdown-item-${index}`)
|
||||||
|
if (option) {
|
||||||
|
option.focus()
|
||||||
|
option.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function onKeyDown() {
|
||||||
|
isOpen.value = true
|
||||||
|
focusItemIndex.value =
|
||||||
|
focusItemIndex.value === null ? 0 : (focusItemIndex.value += 1)
|
||||||
|
if (focusItemIndex.value >= filteredTimezones.value.length) {
|
||||||
|
focusItemIndex.value = 0
|
||||||
|
}
|
||||||
|
scrollIntoOption(focusItemIndex.value)
|
||||||
|
}
|
||||||
|
function onKeyUp() {
|
||||||
|
isOpen.value = true
|
||||||
|
focusItemIndex.value =
|
||||||
|
focusItemIndex.value === null
|
||||||
|
? filteredTimezones.value.length - 1
|
||||||
|
: (focusItemIndex.value -= 1)
|
||||||
|
if (focusItemIndex.value <= -1) {
|
||||||
|
focusItemIndex.value = filteredTimezones.value.length - 1
|
||||||
|
}
|
||||||
|
scrollIntoOption(focusItemIndex.value)
|
||||||
|
}
|
||||||
|
function cancelUpdate() {
|
||||||
|
if (isOpen.value) {
|
||||||
|
isOpen.value = false
|
||||||
|
timezone.value = input.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.input,
|
() => props.input,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
"HIDE_PASSWORD": "Passwort verbergen",
|
"HIDE_PASSWORD": "Passwort verbergen",
|
||||||
"INVALID_TOKEN": "Ungültiges Token, bitte fordere ein neues Passworts an.",
|
"INVALID_TOKEN": "Ungültiges Token, bitte fordere ein neues Passworts an.",
|
||||||
"I_WANT_TO_DELETE_MY_ACCOUNT": "Ich möchte meinen Account löschen",
|
"I_WANT_TO_DELETE_MY_ACCOUNT": "Ich möchte meinen Account löschen",
|
||||||
"LANGUAGE": "Sprache",
|
"LANGUAGE": "Sprache | Sprachen",
|
||||||
"LAST_PRIVACY_POLICY_TO_VALIDATE": "Die Datenschutzrichtlinie wurde aktualisiert, bitte {0} sie vor dem Fortfahren.",
|
"LAST_PRIVACY_POLICY_TO_VALIDATE": "Die Datenschutzrichtlinie wurde aktualisiert, bitte {0} sie vor dem Fortfahren.",
|
||||||
"LOGIN": "Anmeldung",
|
"LOGIN": "Anmeldung",
|
||||||
"LOGOUT": "Abmelden",
|
"LOGOUT": "Abmelden",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
"HIDE_PASSWORD": "hide password",
|
"HIDE_PASSWORD": "hide password",
|
||||||
"INVALID_TOKEN": "Invalid token, please request a new password reset.",
|
"INVALID_TOKEN": "Invalid token, please request a new password reset.",
|
||||||
"I_WANT_TO_DELETE_MY_ACCOUNT": "I want to delete my account",
|
"I_WANT_TO_DELETE_MY_ACCOUNT": "I want to delete my account",
|
||||||
"LANGUAGE": "Language",
|
"LANGUAGE": "Language | Languages",
|
||||||
"LAST_PRIVACY_POLICY_TO_VALIDATE": "The privacy policy has been updated, please {0} it before proceeding.",
|
"LAST_PRIVACY_POLICY_TO_VALIDATE": "The privacy policy has been updated, please {0} it before proceeding.",
|
||||||
"LOGIN": "Login",
|
"LOGIN": "Login",
|
||||||
"LOGOUT": "Logout",
|
"LOGOUT": "Logout",
|
||||||
@@ -123,7 +123,7 @@
|
|||||||
"LIGHT": "Light"
|
"LIGHT": "Light"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"TIMEZONE": "Timezone",
|
"TIMEZONE": "Timezone | Timezones",
|
||||||
"UNITS": {
|
"UNITS": {
|
||||||
"IMPERIAL": "Imperial system (ft, mi, mph, °F)",
|
"IMPERIAL": "Imperial system (ft, mi, mph, °F)",
|
||||||
"LABEL": "Units for distance",
|
"LABEL": "Units for distance",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
"HIDE_PASSWORD": "ocultar contraseña",
|
"HIDE_PASSWORD": "ocultar contraseña",
|
||||||
"INVALID_TOKEN": "Clave secreta no válida, solicita un nuevo restablecimiento de contraseña.",
|
"INVALID_TOKEN": "Clave secreta no válida, solicita un nuevo restablecimiento de contraseña.",
|
||||||
"I_WANT_TO_DELETE_MY_ACCOUNT": "Quiero eliminar mi cuenta",
|
"I_WANT_TO_DELETE_MY_ACCOUNT": "Quiero eliminar mi cuenta",
|
||||||
"LANGUAGE": "Idioma",
|
"LANGUAGE": "Idioma | Idiomas",
|
||||||
"LAST_PRIVACY_POLICY_TO_VALIDATE": "La política de privacidad ha sido actualizada, {0} antes de continuar.",
|
"LAST_PRIVACY_POLICY_TO_VALIDATE": "La política de privacidad ha sido actualizada, {0} antes de continuar.",
|
||||||
"LOGIN": "Acceder",
|
"LOGIN": "Acceder",
|
||||||
"LOGOUT": "Cerrar sesión",
|
"LOGOUT": "Cerrar sesión",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
"HIDE_PASSWORD": "masquer le mot de passe",
|
"HIDE_PASSWORD": "masquer le mot de passe",
|
||||||
"INVALID_TOKEN": "Jeton invalide, veuillez demander une nouvelle réinitialisation de mot de passe.",
|
"INVALID_TOKEN": "Jeton invalide, veuillez demander une nouvelle réinitialisation de mot de passe.",
|
||||||
"I_WANT_TO_DELETE_MY_ACCOUNT": "Je souhaite supprimer mon compte",
|
"I_WANT_TO_DELETE_MY_ACCOUNT": "Je souhaite supprimer mon compte",
|
||||||
"LANGUAGE": "Langue",
|
"LANGUAGE": "Langue | Langues",
|
||||||
"LAST_PRIVACY_POLICY_TO_VALIDATE": "La politique de confidentialité a été mise à jour. Veuillez l'{0} avant de poursuivre.",
|
"LAST_PRIVACY_POLICY_TO_VALIDATE": "La politique de confidentialité a été mise à jour. Veuillez l'{0} avant de poursuivre.",
|
||||||
"LOGIN": "Se connecter",
|
"LOGIN": "Se connecter",
|
||||||
"LOGOUT": "Se déconnecter",
|
"LOGOUT": "Se déconnecter",
|
||||||
@@ -123,7 +123,7 @@
|
|||||||
"LIGHT": "Clair"
|
"LIGHT": "Clair"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"TIMEZONE": "Fuseau horaire",
|
"TIMEZONE": "Fuseau horaire | Fuseaux horaires",
|
||||||
"UNITS": {
|
"UNITS": {
|
||||||
"IMPERIAL": "Système impérial (ft, mi, mph, °F)",
|
"IMPERIAL": "Système impérial (ft, mi, mph, °F)",
|
||||||
"LABEL": "Unités pour les distances",
|
"LABEL": "Unités pour les distances",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
"HIDE_PASSWORD": "agochar contrasinal",
|
"HIDE_PASSWORD": "agochar contrasinal",
|
||||||
"INVALID_TOKEN": "Token non válido, solicita un novo restablecemento de contrasinal.",
|
"INVALID_TOKEN": "Token non válido, solicita un novo restablecemento de contrasinal.",
|
||||||
"I_WANT_TO_DELETE_MY_ACCOUNT": "Quero eliminar a miña conta",
|
"I_WANT_TO_DELETE_MY_ACCOUNT": "Quero eliminar a miña conta",
|
||||||
"LANGUAGE": "Idioma",
|
"LANGUAGE": "Idioma | Idiomas",
|
||||||
"LAST_PRIVACY_POLICY_TO_VALIDATE": "Actualizouse a política de privacidade, podes {0} antes de continuar.",
|
"LAST_PRIVACY_POLICY_TO_VALIDATE": "Actualizouse a política de privacidade, podes {0} antes de continuar.",
|
||||||
"LOGIN": "Acceso",
|
"LOGIN": "Acceso",
|
||||||
"LOGOUT": "Pechar sesión",
|
"LOGOUT": "Pechar sesión",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
"FILTER_ON_USERNAME": "Filtra per username",
|
"FILTER_ON_USERNAME": "Filtra per username",
|
||||||
"HIDE_PASSWORD": "nascondi password",
|
"HIDE_PASSWORD": "nascondi password",
|
||||||
"INVALID_TOKEN": "Token invalido, per favore richiedi un nuovo reset della password.",
|
"INVALID_TOKEN": "Token invalido, per favore richiedi un nuovo reset della password.",
|
||||||
"LANGUAGE": "Lingua",
|
"LANGUAGE": "Lingua | Le lingue",
|
||||||
"LOGIN": "Login",
|
"LOGIN": "Login",
|
||||||
"LOGOUT": "Logout",
|
"LOGOUT": "Logout",
|
||||||
"LOG_IN": "log in",
|
"LOG_IN": "log in",
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"HIDE_PASSWORD": "skjul passord",
|
"HIDE_PASSWORD": "skjul passord",
|
||||||
"INVALID_TOKEN": "Ugyldig symbol. Forespør ny tilbakestilling av passord.",
|
"INVALID_TOKEN": "Ugyldig symbol. Forespør ny tilbakestilling av passord.",
|
||||||
"I_WANT_TO_DELETE_MY_ACCOUNT": "Jeg vil slette kontoen min",
|
"I_WANT_TO_DELETE_MY_ACCOUNT": "Jeg vil slette kontoen min",
|
||||||
"LANGUAGE": "Språk",
|
"LANGUAGE": "Språk | Språk",
|
||||||
"LOGIN": "Logg inn",
|
"LOGIN": "Logg inn",
|
||||||
"LOGOUT": "Logg ut",
|
"LOGOUT": "Logg ut",
|
||||||
"LOGOUT_CONFIRMATION": "Vil du logge ut?",
|
"LOGOUT_CONFIRMATION": "Vil du logge ut?",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
"HIDE_PASSWORD": "verberg wachtwoord",
|
"HIDE_PASSWORD": "verberg wachtwoord",
|
||||||
"INVALID_TOKEN": "Ongeldig token, vraag een nieuwe wachtwoord reset aan.",
|
"INVALID_TOKEN": "Ongeldig token, vraag een nieuwe wachtwoord reset aan.",
|
||||||
"I_WANT_TO_DELETE_MY_ACCOUNT": "Ik wil mijn account verwijderen",
|
"I_WANT_TO_DELETE_MY_ACCOUNT": "Ik wil mijn account verwijderen",
|
||||||
"LANGUAGE": "Taal",
|
"LANGUAGE": "Taal | Talen",
|
||||||
"LAST_PRIVACY_POLICY_TO_VALIDATE": "Het privacybeleid werd aangepast, gelieve te {0} voor verdergaan.",
|
"LAST_PRIVACY_POLICY_TO_VALIDATE": "Het privacybeleid werd aangepast, gelieve te {0} voor verdergaan.",
|
||||||
"LOGIN": "Inloggen",
|
"LOGIN": "Inloggen",
|
||||||
"LOGOUT": "Uitloggen",
|
"LOGOUT": "Uitloggen",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
"HIDE_PASSWORD": "ukryj hasło",
|
"HIDE_PASSWORD": "ukryj hasło",
|
||||||
"INVALID_TOKEN": "Niepoprawny token, proszę zlecić nowy reset hasła.",
|
"INVALID_TOKEN": "Niepoprawny token, proszę zlecić nowy reset hasła.",
|
||||||
"I_WANT_TO_DELETE_MY_ACCOUNT": "Chcę usunąć swoje konto",
|
"I_WANT_TO_DELETE_MY_ACCOUNT": "Chcę usunąć swoje konto",
|
||||||
"LANGUAGE": "Język",
|
"LANGUAGE": "Język | Języki",
|
||||||
"LAST_PRIVACY_POLICY_TO_VALIDATE": "Polityka prywatności uległa zmianie, proszę {0} ją przed przejściem dalej.",
|
"LAST_PRIVACY_POLICY_TO_VALIDATE": "Polityka prywatności uległa zmianie, proszę {0} ją przed przejściem dalej.",
|
||||||
"LOGIN": "Zaloguj",
|
"LOGIN": "Zaloguj",
|
||||||
"LOGOUT": "Wyloguj",
|
"LOGOUT": "Wyloguj",
|
||||||
|
|||||||
Reference in New Issue
Block a user