Merge master into this branch.

This commit is contained in:
elweyn 2022-08-15 11:03:58 +02:00
commit b41f34a3dd
18 changed files with 484 additions and 22 deletions

View File

@ -25,6 +25,14 @@
"keepFileExt" : true, "keepFileExt" : true,
"fileNameSep" : "_" "fileNameSep" : "_"
}, },
"klicktipp":
{
"type": "dateFile",
"filename": "../logs/backend/klicktipp.log",
"pattern": "%d{ISO8601} %p %c %X{user} %f:%l %m",
"keepFileExt" : true,
"fileNameSep" : "_"
},
"errorFile": "errorFile":
{ {
"type": "dateFile", "type": "dateFile",
@ -90,6 +98,17 @@
"level": "debug", "level": "debug",
"enableCallStack": true "enableCallStack": true
}, },
"klicktipp":
{
"appenders":
[
"klicktipp",
"out",
"errors"
],
"level": "debug",
"enableCallStack": true
},
"http": "http":
{ {
"appenders": "appenders":

View File

@ -30,7 +30,9 @@ export enum RIGHTS {
LIST_CONTRIBUTIONS = 'LIST_CONTRIBUTIONS', LIST_CONTRIBUTIONS = 'LIST_CONTRIBUTIONS',
LIST_ALL_CONTRIBUTIONS = 'LIST_ALL_CONTRIBUTIONS', LIST_ALL_CONTRIBUTIONS = 'LIST_ALL_CONTRIBUTIONS',
UPDATE_CONTRIBUTION = 'UPDATE_CONTRIBUTION', UPDATE_CONTRIBUTION = 'UPDATE_CONTRIBUTION',
LIST_CONTRIBUTION_LINKS = 'LIST_CONTRIBUTION_LINKS',
SEARCH_ADMIN_USERS = 'SEARCH_ADMIN_USERS', SEARCH_ADMIN_USERS = 'SEARCH_ADMIN_USERS',
// Admin // Admin
SEARCH_USERS = 'SEARCH_USERS', SEARCH_USERS = 'SEARCH_USERS',
SET_USER_ROLE = 'SET_USER_ROLE', SET_USER_ROLE = 'SET_USER_ROLE',
@ -46,7 +48,6 @@ export enum RIGHTS {
CREATION_TRANSACTION_LIST = 'CREATION_TRANSACTION_LIST', CREATION_TRANSACTION_LIST = 'CREATION_TRANSACTION_LIST',
LIST_TRANSACTION_LINKS_ADMIN = 'LIST_TRANSACTION_LINKS_ADMIN', LIST_TRANSACTION_LINKS_ADMIN = 'LIST_TRANSACTION_LINKS_ADMIN',
CREATE_CONTRIBUTION_LINK = 'CREATE_CONTRIBUTION_LINK', CREATE_CONTRIBUTION_LINK = 'CREATE_CONTRIBUTION_LINK',
LIST_CONTRIBUTION_LINKS = 'LIST_CONTRIBUTION_LINKS',
DELETE_CONTRIBUTION_LINK = 'DELETE_CONTRIBUTION_LINK', DELETE_CONTRIBUTION_LINK = 'DELETE_CONTRIBUTION_LINK',
UPDATE_CONTRIBUTION_LINK = 'UPDATE_CONTRIBUTION_LINK', UPDATE_CONTRIBUTION_LINK = 'UPDATE_CONTRIBUTION_LINK',
} }

View File

@ -28,7 +28,11 @@ export const ROLE_USER = new Role('user', [
RIGHTS.LIST_CONTRIBUTIONS, RIGHTS.LIST_CONTRIBUTIONS,
RIGHTS.LIST_ALL_CONTRIBUTIONS, RIGHTS.LIST_ALL_CONTRIBUTIONS,
RIGHTS.UPDATE_CONTRIBUTION, RIGHTS.UPDATE_CONTRIBUTION,
<<<<<<< HEAD
RIGHTS.SEARCH_ADMIN_USERS, RIGHTS.SEARCH_ADMIN_USERS,
=======
RIGHTS.LIST_CONTRIBUTION_LINKS,
>>>>>>> master
]) ])
export const ROLE_ADMIN = new Role('admin', Object.values(RIGHTS)) // all rights export const ROLE_ADMIN = new Role('admin', Object.values(RIGHTS)) // all rights

View File

@ -1857,11 +1857,17 @@ describe('AdminResolver', () => {
}) })
}) })
// TODO: Set this test in new location to have datas
describe('listContributionLinks', () => { describe('listContributionLinks', () => {
it('returns an error', async () => { it('returns an empty object', async () => {
await expect(query({ query: listContributionLinks })).resolves.toEqual( await expect(query({ query: listContributionLinks })).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [new GraphQLError('401 Unauthorized')], data: {
listContributionLinks: {
count: 0,
links: [],
},
},
}), }),
) )
}) })

View File

@ -501,7 +501,7 @@ export class AdminResolver {
order: { updatedAt: 'DESC' }, order: { updatedAt: 'DESC' },
}) })
optInCode = await checkOptInCode(optInCode, user.id) optInCode = await checkOptInCode(optInCode, user)
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const emailSent = await sendAccountActivationEmail({ const emailSent = await sendAccountActivationEmail({

View File

@ -198,7 +198,7 @@ describe('UserResolver', () => {
it('sets "de" as default language', async () => { it('sets "de" as default language', async () => {
await mutate({ await mutate({
mutation: createUser, mutation: createUser,
variables: { ...variables, email: 'bibi@bloxberg.de', language: 'es' }, variables: { ...variables, email: 'bibi@bloxberg.de', language: 'fr' },
}) })
await expect(User.find()).resolves.toEqual( await expect(User.find()).resolves.toEqual(
expect.arrayContaining([ expect.arrayContaining([

View File

@ -47,7 +47,7 @@ const isPassword = (password: string): boolean => {
return !!password.match(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^a-zA-Z0-9 \\t\\n\\r]).{8,}$/) return !!password.match(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^a-zA-Z0-9 \\t\\n\\r]).{8,}$/)
} }
const LANGUAGES = ['de', 'en'] const LANGUAGES = ['de', 'en', 'es']
const DEFAULT_LANGUAGE = 'de' const DEFAULT_LANGUAGE = 'de'
const isLanguage = (language: string): boolean => { const isLanguage = (language: string): boolean => {
return LANGUAGES.includes(language) return LANGUAGES.includes(language)
@ -191,7 +191,7 @@ const newEmailOptIn = (userId: number): LoginEmailOptIn => {
// if optIn does not exits, it is created // if optIn does not exits, it is created
export const checkOptInCode = async ( export const checkOptInCode = async (
optInCode: LoginEmailOptIn | undefined, optInCode: LoginEmailOptIn | undefined,
userId: number, user: DbUser,
optInType: OptInType = OptInType.EMAIL_OPT_IN_REGISTER, optInType: OptInType = OptInType.EMAIL_OPT_IN_REGISTER,
): Promise<LoginEmailOptIn> => { ): Promise<LoginEmailOptIn> => {
logger.info(`checkOptInCode... ${optInCode}`) logger.info(`checkOptInCode... ${optInCode}`)
@ -211,15 +211,18 @@ export const checkOptInCode = async (
optInCode.updatedAt = new Date() optInCode.updatedAt = new Date()
optInCode.resendCount++ optInCode.resendCount++
} else { } else {
logger.trace('create new OptIn for userId=' + userId) logger.trace('create new OptIn for userId=' + user.id)
optInCode = newEmailOptIn(userId) optInCode = newEmailOptIn(user.id)
} }
if (user.emailChecked) {
optInCode.emailOptInTypeId = optInType optInCode.emailOptInTypeId = optInType
}
await LoginEmailOptIn.save(optInCode).catch(() => { await LoginEmailOptIn.save(optInCode).catch(() => {
logger.error('Unable to save optin code= ' + optInCode) logger.error('Unable to save optin code= ' + optInCode)
throw new Error('Unable to save optin code.') throw new Error('Unable to save optin code.')
}) })
logger.debug(`checkOptInCode...successful: ${optInCode} for userid=${userId}`) logger.debug(`checkOptInCode...successful: ${optInCode} for userid=${user.id}`)
return optInCode return optInCode
} }
@ -497,7 +500,7 @@ export class UserResolver {
userId: user.id, userId: user.id,
}) })
optInCode = await checkOptInCode(optInCode, user.id, OptInType.EMAIL_OPT_IN_RESET_PASSWORD) optInCode = await checkOptInCode(optInCode, user, OptInType.EMAIL_OPT_IN_RESET_PASSWORD)
logger.info(`optInCode for ${email}=${optInCode}`) logger.info(`optInCode for ${email}=${optInCode}`)
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const emailSent = await sendResetPasswordEmailMailer({ const emailSent = await sendResetPasswordEmailMailer({

View File

@ -2,6 +2,7 @@ import { MiddlewareFn } from 'type-graphql'
import { /* klicktippSignIn, */ getKlickTippUser } from '@/apis/KlicktippController' import { /* klicktippSignIn, */ getKlickTippUser } from '@/apis/KlicktippController'
import { KlickTipp } from '@model/KlickTipp' import { KlickTipp } from '@model/KlickTipp'
import CONFIG from '@/config' import CONFIG from '@/config'
import { klickTippLogger as logger } from '@/server/logger'
// export const klicktippRegistrationMiddleware: MiddlewareFn = async ( // export const klicktippRegistrationMiddleware: MiddlewareFn = async (
// // Only for demo // // Only for demo
@ -29,7 +30,9 @@ export const klicktippNewsletterStateMiddleware: MiddlewareFn = async (
if (klickTippUser) { if (klickTippUser) {
klickTipp = new KlickTipp(klickTippUser) klickTipp = new KlickTipp(klickTippUser)
} }
} catch (err) {} } catch (err) {
logger.error(`There is no user for (email='${result.email}') ${err}`)
}
} }
result.klickTipp = klickTipp result.klickTipp = klickTipp
return result return result

View File

@ -12,7 +12,8 @@ log4js.configure(options)
const apolloLogger = log4js.getLogger('apollo') const apolloLogger = log4js.getLogger('apollo')
const backendLogger = log4js.getLogger('backend') const backendLogger = log4js.getLogger('backend')
const klickTippLogger = log4js.getLogger('klicktipp')
backendLogger.addContext('user', 'unknown') backendLogger.addContext('user', 'unknown')
export { apolloLogger, backendLogger } export { apolloLogger, backendLogger, klickTippLogger }

Binary file not shown.

View File

@ -45,7 +45,7 @@ describe('LanguageSwitch', () => {
expect(wrapper.find('div.language-switch').exists()).toBeTruthy() expect(wrapper.find('div.language-switch').exists()).toBeTruthy()
}) })
describe('with locales en and de', () => { describe('with locales en, de and es', () => {
describe('empty store', () => { describe('empty store', () => {
describe('navigator language is "en-US"', () => { describe('navigator language is "en-US"', () => {
const languageGetter = jest.spyOn(navigator, 'language', 'get') const languageGetter = jest.spyOn(navigator, 'language', 'get')
@ -69,11 +69,22 @@ describe('LanguageSwitch', () => {
}) })
}) })
describe('navigator language is "es-ES" (not supported)', () => { describe('navigator language is "es-ES"', () => {
const languageGetter = jest.spyOn(navigator, 'language', 'get')
it('shows Español as language ', async () => {
languageGetter.mockReturnValue('es-ES')
wrapper.vm.setCurrentLanguage()
await wrapper.vm.$nextTick()
expect(wrapper.find('button.dropdown-toggle').text()).toBe('Español - es')
})
})
describe('navigator language is "fr-FR" (not supported)', () => {
const languageGetter = jest.spyOn(navigator, 'language', 'get') const languageGetter = jest.spyOn(navigator, 'language', 'get')
it('shows English as language ', async () => { it('shows English as language ', async () => {
languageGetter.mockReturnValue('es-ES') languageGetter.mockReturnValue('fr-FR')
wrapper.vm.setCurrentLanguage() wrapper.vm.setCurrentLanguage()
await wrapper.vm.$nextTick() await wrapper.vm.$nextTick()
expect(wrapper.find('button.dropdown-toggle').text()).toBe('English - en') expect(wrapper.find('button.dropdown-toggle').text()).toBe('English - en')
@ -101,9 +112,18 @@ describe('LanguageSwitch', () => {
}) })
}) })
describe('language "es" in store', () => {
it('shows Español as language', async () => {
wrapper.vm.$store.state.language = 'es'
wrapper.vm.setCurrentLanguage()
await wrapper.vm.$nextTick()
expect(wrapper.find('button.dropdown-toggle').text()).toBe('Español - es')
})
})
describe('dropdown menu', () => { describe('dropdown menu', () => {
it('has English and German as languages to choose', () => { it('has English and German as languages to choose', () => {
expect(wrapper.findAll('li')).toHaveLength(2) expect(wrapper.findAll('li')).toHaveLength(3)
}) })
it('has English as first language to choose', () => { it('has English as first language to choose', () => {
@ -113,6 +133,10 @@ describe('LanguageSwitch', () => {
it('has German as second language to choose', () => { it('has German as second language to choose', () => {
expect(wrapper.findAll('li').at(1).text()).toBe('Deutsch') expect(wrapper.findAll('li').at(1).text()).toBe('Deutsch')
}) })
it('has Español as second language to choose', () => {
expect(wrapper.findAll('li').at(2).text()).toBe('Español')
})
}) })
}) })

View File

@ -66,10 +66,19 @@ describe('LanguageSwitch', () => {
expect(wrapper.findAll('span.locales').at(1).text()).toBe('Deutsch') expect(wrapper.findAll('span.locales').at(1).text()).toBe('Deutsch')
}) })
}) })
describe('navigator language is "es-ES" (not supported)', () => { describe('navigator language is "es-ES"', () => {
const languageGetter = jest.spyOn(navigator, 'language', 'get')
it('shows Español as language ', async () => {
languageGetter.mockReturnValue('es-ES')
wrapper.vm.setCurrentLanguage()
await wrapper.vm.$nextTick()
expect(wrapper.findAll('span.locales').at(2).text()).toBe('Español')
})
})
describe('navigator language is "fr-FR" (not supported)', () => {
const languageGetter = jest.spyOn(navigator, 'language', 'get') const languageGetter = jest.spyOn(navigator, 'language', 'get')
it('shows English as language ', async () => { it('shows English as language ', async () => {
languageGetter.mockReturnValue('es-ES') languageGetter.mockReturnValue('fr-FR')
wrapper.vm.setCurrentLanguage() wrapper.vm.setCurrentLanguage()
await wrapper.vm.$nextTick() await wrapper.vm.$nextTick()
expect(wrapper.findAll('span.locales').at(0).text()).toBe('English') expect(wrapper.findAll('span.locales').at(0).text()).toBe('English')
@ -93,9 +102,17 @@ describe('LanguageSwitch', () => {
expect(wrapper.findAll('span.locales').at(1).text()).toBe('Deutsch') expect(wrapper.findAll('span.locales').at(1).text()).toBe('Deutsch')
}) })
}) })
describe('language "es" in store', () => {
it('shows Español as language', async () => {
wrapper.vm.$store.state.language = 'es'
wrapper.vm.setCurrentLanguage()
await wrapper.vm.$nextTick()
expect(wrapper.findAll('span.locales').at(2).text()).toBe('Español')
})
})
describe('language menu', () => { describe('language menu', () => {
it('has English and German as languages to choose', () => { it('has English, German and Español as languages to choose', () => {
expect(wrapper.findAll('span.locales')).toHaveLength(2) expect(wrapper.findAll('span.locales')).toHaveLength(3)
}) })
it('has English as first language to choose', () => { it('has English as first language to choose', () => {
expect(wrapper.findAll('span.locales').at(0).text()).toBe('English') expect(wrapper.findAll('span.locales').at(0).text()).toBe('English')
@ -103,6 +120,9 @@ describe('LanguageSwitch', () => {
it('has German as second language to choose', () => { it('has German as second language to choose', () => {
expect(wrapper.findAll('span.locales').at(1).text()).toBe('Deutsch') expect(wrapper.findAll('span.locales').at(1).text()).toBe('Deutsch')
}) })
it('has Español as third language to choose', () => {
expect(wrapper.findAll('span.locales').at(2).text()).toBe('Español')
})
}) })
}) })

View File

@ -16,6 +16,7 @@ export default {
options: [ options: [
{ value: 'de', text: this.$t('settings.language.de') }, { value: 'de', text: this.$t('settings.language.de') },
{ value: 'en', text: this.$t('settings.language.en') }, { value: 'en', text: this.$t('settings.language.en') },
{ value: 'es', text: this.$t('settings.language.es') },
], ],
} }
}, },

View File

@ -3,6 +3,7 @@ import VueI18n from 'vue-i18n'
import en from 'vee-validate/dist/locale/en' import en from 'vee-validate/dist/locale/en'
import de from 'vee-validate/dist/locale/de' import de from 'vee-validate/dist/locale/de'
import es from 'vee-validate/dist/locale/es'
Vue.use(VueI18n) Vue.use(VueI18n)
@ -26,6 +27,12 @@ function loadLocaleMessages() {
...messages[locale], ...messages[locale],
} }
} }
if (locale === 'es') {
messages[locale] = {
validations: es,
...messages[locale],
}
}
} }
}) })
return messages return messages
@ -58,6 +65,19 @@ const numberFormats = {
useGrouping: false, useGrouping: false,
}, },
}, },
es: {
decimal: {
style: 'decimal',
minimumFractionDigits: 2,
maximumFractionDigits: 2,
},
ungroupedDecimal: {
style: 'decimal',
minimumFractionDigits: 2,
maximumFractionDigits: 2,
useGrouping: false,
},
},
} }
const dateTimeFormats = { const dateTimeFormats = {
@ -117,6 +137,34 @@ const dateTimeFormats = {
year: 'numeric', year: 'numeric',
}, },
}, },
es: {
short: {
day: 'numeric',
month: 'numeric',
year: 'numeric',
},
long: {
day: 'numeric',
month: 'long',
year: 'numeric',
weekday: 'long',
hour: 'numeric',
minute: 'numeric',
},
monthShort: {
month: 'short',
},
month: {
month: 'long',
},
year: {
year: 'numeric',
},
monthAndYear: {
month: 'long',
year: 'numeric',
},
},
} }
export default new VueI18n({ export default new VueI18n({

View File

@ -246,6 +246,7 @@
"changeLanguage": "Sprache ändern", "changeLanguage": "Sprache ändern",
"de": "Deutsch", "de": "Deutsch",
"en": "English", "en": "English",
"es": "Español",
"success": "Deine Sprache wurde erfolgreich geändert." "success": "Deine Sprache wurde erfolgreich geändert."
}, },
"name": { "name": {

View File

@ -246,6 +246,7 @@
"changeLanguage": "Change language", "changeLanguage": "Change language",
"de": "Deutsch", "de": "Deutsch",
"en": "English", "en": "English",
"es": "Español",
"success": "Your language has been successfully updated." "success": "Your language has been successfully updated."
}, },
"name": { "name": {

View File

@ -0,0 +1,324 @@
{
"100": "100%",
"1000thanks": "1000 Gracias, por estar con nosotros!",
"125": "125%",
"85": "85%",
"advanced-calculation": "Proyección",
"auth": {
"left": {
"dignity": "Dignidad",
"donation": "Donación",
"gratitude": "Gratitud",
"hasAccount": "Ya estas registrado?",
"hereLogin": "Regístrate aquí",
"learnMore": "Infórmate aquí …",
"oneDignity": "Damos los unos a los otros y agradecemos con Gradido.",
"oneDonation": "Eres un regalo para la comunidad. 1000 gracias por estar con nosotros.",
"oneGratitude": "Por los demás, por toda la humanidad, por la naturaleza."
},
"navbar": {
"aboutGradido": "Sobre Gradido"
}
},
"back": "Volver",
"community": {
"choose-another-community": "Escoger otra comunidad",
"community": "Comunidad",
"continue-to-registration": "Continuar con el registro",
"current-community": "Comunidad actual",
"myContributions": "Mis contribuciones al bien común",
"other-communities": "Otras comunidades",
"submitContribution": "Aportar una contribución",
"switch-to-this-community": "cambiar a esta comunidad"
},
"contribution": {
"activity": "Actividad",
"alert": {
"communityNoteList": "Aquí encontrarás todas las contribuciones enviadas y confirmadas de todos los miembros de esta comunidad.",
"confirm": "confirmado",
"myContributionNoteList": "Puedes editar o eliminar las contribuciones enviadas que aún no han sido confirmadas en cualquier momento.",
"myContributionNoteSupport": "Pronto existirá la posibilidad de que puedas dialogar con los moderadores. Si tienes algún problema ahora, ponte en contacto con el equipo de asistencia.",
"pending": "Enviado y a la espera de confirmación",
"rejected": "rechazado"
},
"date": "Contribución para:",
"delete": "Eliminar la contribución. ¿Estás seguro?",
"deleted": "¡La contribución ha sido borrada! Pero seguirá siendo visible.",
"formText": {
"bringYourTalentsTo": "¡Contribuye a la comunidad con tus talentos! Premiamos tu compromiso voluntario con 20 GDD por hora hasta un máximo de 1.000 GDD al mes.",
"describeYourCommunity": "¡Describe tu contribución al bien-común con detalles de las horas e introduce una cantidad de 20 GDD por hora! Tras la confirmación de un moderador, el importe se abonará en tu cuenta.",
"maxGDDforMonth": "Sólo puede presentar un máximo de {amount} GDD para el mes seleccionado.",
"openAmountForMonth": "Para <b>{monthAndYear}</b> aún puedes presentar <b>{creation}</b> GDD.",
"yourContribution": "Tu contribución a la comunidad."
},
"noDateSelected": "Elige cualquier fecha del mes.",
"selectDate": "¿Cuando fue tu contribución?",
"submit": "Enviar",
"submitted": "Tu contribución ha sido enviada.",
"updated": "La contribución se modificó.",
"yourActivity": "¡Por favor, introduce una actividad!"
},
"contribution-link": {
"thanksYouWith": "agradecidos con"
},
"decay": {
"before_startblock_transaction": "Esta transacción no implica disminución en su valor.",
"calculation_decay": "Cálculo de la disminución gradual del valor",
"calculation_total": "Cálculo de la suma total",
"decay": "Disminución gradual del valor",
"decay_introduced": "La disminución gradual empezó el:",
"decay_since_last_transaction": "Disminución gradual",
"last_transaction": "Transacción anterior",
"past_time": "Tiempo transcurrido",
"Starting_block_decay": "Startblock disminución gradual",
"total": "Total",
"types": {
"creation": "Creado",
"noDecay": "sin disminución gradual",
"receive": "Recibido",
"send": "Enviado"
}
},
"delete": "Eliminar",
"em-dash": "—",
"error": {
"email-already-sent": "Ya te hemos enviado un correo electrónico hace menos de 10 minutos.",
"empty-transactionlist": "Ha habido un error en la transmisión del número de sus transacciones.",
"error": "Error!",
"no-account": "Lamentablemente no hemos podido encontrar una cuenta (activada) con estos datos.",
"no-transactionlist": "Lamentablemente, hubo un error. No se ha transmitido ninguna transacción desde el servidor.",
"no-user": "No hay usuario con estas referencias.",
"session-expired": "La sesión se cerró por razones de seguridad.",
"unknown-error": "Error desconocido: "
},
"followUs": "sigue nos:",
"footer": {
"app_version": "App versión {version}",
"copyright": {
"link": "Gradido-Akademie",
"year": "© {year}"
},
"imprint": "Aviso legal",
"privacy_policy": "Protección de Datos",
"short_hash": "({shortHash})",
"whitepaper": "Whitepaper"
},
"form": {
"amount": "Importe",
"at": "am",
"cancel": "Cancelar",
"change": "Cambiar",
"check_now": "Revisar",
"close": "Cerrar",
"current_balance": "Saldo de cuenta actual",
"date": "Fecha",
"description": "Descripción",
"email": "E-Mail",
"firstname": "Nombre",
"from": "De",
"generate_now": "crear ahora",
"lastname": "Apellido",
"mandatoryField": "campo obligatorio",
"memo": "Mensaje",
"message": "Noticia",
"new_balance": "Saldo de cuenta nuevo depués de confirmación",
"no_gdd_available": "No dispones de GDD para enviar.",
"password": "Contraseña",
"passwordRepeat": "Repetir contraseña",
"password_new": "contraseña nueva",
"password_new_repeat": "Repetir contraseña nueva",
"password_old": "contraseña antigua",
"recipient": "Destinatario",
"reset": "Restablecer",
"save": "Guardar",
"scann_code": "<strong>QR Code Scanner</strong> - Escanea el código QR de tu pareja",
"sender": "Remitente",
"send_check": "Confirma tu transacción. Por favor revisa toda la información nuevamente!",
"send_now": "Enviar ahora",
"send_transaction_error": "Desafortunadamente, la transacción no se pudo ejecutar!",
"send_transaction_success": "Su transacción fue ejecutada con éxito",
"sorry": "Disculpa",
"thx": "Gracias",
"time": "Tiempo",
"to": "hasta",
"to1": "para",
"validation": {
"gddSendAmount": "El campo {_field_} debe ser un número entre {min} y {max} con un máximo de dos decimales",
"is-not": "No es posible transferirte Gradidos a ti mismo",
"usernmae-regex": "El nombre de usuario debe comenzar con una letra seguida de al menos dos caracteres alfanuméricos.",
"usernmae-unique": "Este nombre de usuario ya está adjudicado."
},
"your_amount": "Tu importe"
},
"GDD": "GDD",
"gdd_per_link": {
"choose-amount": "Selecciona una cantidad que te gustaría enviar a través de un enlace. También puedes ingresar un mensaje. Cuando haces clic en 'Generar ahora', se crea un enlace que puedes enviar.",
"copy-link": "Copiar enlace",
"copy-link-with-text": "Copiar texto y enlace",
"created": "El enlace ha sido creado",
"credit-your-gradido": "Para que se te acrediten los Gradidos, haz clic en el enlace!",
"decay-14-day": "Disminución gradual por 14 días",
"delete-the-link": "Eliminar el enlace?",
"deleted": "El enlace ha sido eliminado!",
"expiredOn": "Vencido el:",
"has-account": "Ya tienes una cuenta Gradido?",
"header": "Transferir Gradidos por medio de un enlace",
"isFree": "Gradido es gratis en todo el mundo.",
"link-and-text-copied": "El enlace y su mensaje se han copiado en el portapapeles. Ahora puedes ponerlo en un correo electrónico o mensaje.",
"link-copied": "El enlace se ha copiado en el portapapeles. Ahora puedes pegarlo en un correo electrónico o mensaje.",
"link-deleted": "El enlace se eliminó el {date}.",
"link-expired": "El enlace ya no es válido. La validez expiró el {date}.",
"link-overview": "Resumen de enlaces",
"links_count": "Enlaces activos",
"links_sum": "Enlaces abiertos y códigos QR",
"no-account": "Aún no tienes una cuenta de Gradido?",
"no-redeem": "No puedes canjear tu propio enlace!",
"not-copied": "¡Desafortunadamente, su dispositivo no permite copiar! Copie el enlace manualmente!",
"redeem": "Canjear",
"redeem-text": "¿Quieres canjear el importe ahora?",
"redeemed": "¡Canjeado con éxito! Tu cuenta ha sido acreditada con {n} GDD.",
"redeemed-at": "El enlace ya se canjeó el {date}.",
"redeemed-title": "canjeado",
"to-login": "iniciar sesión",
"to-register": "Registre una nueva cuenta.",
"validUntil": "Válido hasta",
"validUntilDate": "El enlace es válido hasta el {date} ."
},
"gdt": {
"calculation": "Cálculo del Gradido Transform",
"contribution": "Importe",
"conversion": "Conversión",
"conversion-gdt-euro": "Conversión Euro / Gradido Transform (GDT)",
"credit": "Abono",
"factor": "Factor",
"formula": "Formula de cálculo",
"funding": "Las donaciones",
"gdt": "Gradido Transform",
"gdt-received": "Gradido Transform (GDT) recibido",
"no-transactions": "Aún no tienes un Gradido Transform (GDT).",
"not-reachable": "No es posible acceder al servidor GDT.",
"publisher": "Tu nuevo miembro referido ha pagado la cuota",
"raise": "Aumento",
"recruited-member": "Miembro invitado"
},
"language": "Idioma",
"link-load": "recargar el último enlace |recargar los últimos {n} enlaces | descargar más {n} enlaces",
"login": "iniciar sesión",
"math": {
"aprox": "~",
"asterisk": "*",
"equal": "=",
"minus": "",
"pipe": "|"
},
"message": {
"activateEmail": "Tu cuenta aún no ha sido activada. Por favor revisa tu correo electrónico y haz clic en el enlace de activación o solicita uno nuevo enlace de activación a través de la página restablecer contraseña.",
"checkEmail": "Tu correo electrónico ha sido verificado con éxito. Puedes registrarte ahora.",
"email": "Te hemos enviado un correo electrónico.",
"errorTitle": "Atención!",
"register": "Ya estás registrado, por favor revisa tu correo electrónico y haz clic en el enlace de activación.",
"reset": "Tu contraseña ha sido cambiada.",
"title": "Gracias!",
"unsetPassword": "Tu contraseña aún no ha sido configurada. Por favor reinícialo."
},
"navigation": {
"admin_area": "Área de administración",
"community": "Comunidad",
"logout": "Salir",
"members_area": "Área de afiliados",
"overview": "Resumen",
"profile": "Mi Perfil",
"send": "Enviar",
"support": "Soporte",
"transactions": "Transacciones"
},
"qrCode": "Código QR",
"send_gdd": "Enviar GDD",
"send_per_link": "Enviar GDD mediante un enlace",
"session": {
"extend": "Permanecer en sesión iniciada",
"lightText": "Si no has realizado ninguna acción durante más de 10 minutos, se cerrará tu sesión por razones de seguridad.",
"logoutIn": "Cerrar sesión en ",
"warningText": "Aún estas?"
},
"settings": {
"language": {
"changeLanguage": "Cambiar idioma",
"de": "Deutsch",
"en": "English",
"es": "Español",
"success": "Tu idioma ha sido cambiado con éxito."
},
"name": {
"change-name": "Cambiar nombre",
"change-success": "Tu nombre ha sido cambiado con éxito."
},
"newsletter": {
"newsletter": "Informaciones por correo electrónico",
"newsletterFalse": "No recibirás informaciones por correo electrónico.",
"newsletterTrue": "Recibirás informaciones por correo electrónico."
},
"password": {
"change-password": "Cambiar contraseña",
"forgot_pwd": "Olvide la contraseña?",
"resend_subtitle": "Su enlace de activación ha caducado. Puedes solicitar uno nuevo aquí.",
"reset": "Restablecer contraseña",
"reset-password": {
"text": "Ahora introduce una nueva contraseña con la que quieras acceder a tu cuenta de Gradido en el futuro.."
},
"send_now": "Enviar",
"set": "Establecer contraseña",
"set-password": {
"text": "Ahora guarda tu nueva contraseña, que podrás utilizar para acceder a tu cuenta de Gradido en el futuro."
},
"subtitle": "Si has olvidado tu contraseña, puedes restablecerla aquí."
}
},
"signin": "Iniciar sesión",
"signup": "Registrarse",
"site": {
"forgotPassword": {
"heading": "Por favor, introduce la dirección de correo electrónico con la que estas registrado en Gradido."
},
"login": {
"heading": "Inicia sesión con tus datos de acceso. Manténlos seguros en todo momento!"
},
"resetPassword": {
"heading": "Por favor, introduce tu contraseña y repítela."
},
"signup": {
"agree": "Acepto la <a href='https://gradido.net/de/datenschutz/' target='_blank' >Política de privacidad</a>.",
"dont_match": "Las contraseñas no coinciden.",
"heading": "Regístrate introduciendo todos los datos completos y en los campos correctos.",
"lowercase": "Se requiere una letra minúscula.",
"minimum": "Al menos 8 caracteres.",
"no-whitespace": "Sin espacios ni tabulaciones.",
"one_number": "Se requiere un número.",
"special-char": "Caracteres especiales requeridos (por ejemplo, _ o &)",
"uppercase": "Letra mayúscula requerida."
}
},
"success": "Lo lograste",
"time": {
"days": "Días",
"hours": "Horas",
"minutes": "Minutos",
"month": "Mes",
"months": "Meses",
"seconds": "Segundos",
"years": "Año"
},
"transaction": {
"gdd-text": "Transacciones Gradido",
"gdt-text": "Transacciones GradidoTransform ",
"nullTransactions": "Todavía no tienes ninguna transacción en tu cuenta.",
"receiverDeleted": "La cuenta del destinatario ha sido eliminada.",
"receiverNotFound": "Destinatario no encontrado",
"show_all": "Ver todas las transacciones de <strong>{count}</strong>"
},
"transaction-link": {
"send_you": "te envía"
},
"via_link": "atraves de un enlace",
"welcome": "Bienvenido a la comunidad."
}

View File

@ -11,6 +11,12 @@ const locales = [
iso: 'de-DE', iso: 'de-DE',
enabled: true, enabled: true,
}, },
{
name: 'Español',
code: 'es',
iso: 'es-ES',
enabled: true,
},
] ]
export default locales export default locales