From c0ea7e0dba14a1edb63b80be0a56a0a14b3fa079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Zi=C3=B3=C5=82ek?= Date: Thu, 21 Nov 2024 14:13:09 +0100 Subject: [PATCH 01/12] feat: language selector prototype --- .../LanguageSelector.module.scss | 3 + .../LanguageSelector/LanguageSelector.tsx | 40 ++++++ .../shared/LanguageSelector/index.ts | 2 + .../LayoutFooter/LayoutFooter.module.scss | 15 +++ .../Layout/LayoutFooter/LayoutFooter.tsx | 19 ++- .../ui/InputSelect/InputSelect.module.scss | 114 +++++++++++++++--- .../components/ui/InputSelect/InputSelect.tsx | 41 +++++-- client/src/components/ui/InputSelect/types.ts | 5 +- client/src/locales/en/translation.json | 6 +- client/src/styles/utils/_mixins.scss | 15 ++- client/src/svg/misc.ts | 6 + .../src/views/ProjectsView/ProjectsView.tsx | 2 +- 12 files changed, 228 insertions(+), 40 deletions(-) create mode 100644 client/src/components/shared/LanguageSelector/LanguageSelector.module.scss create mode 100644 client/src/components/shared/LanguageSelector/LanguageSelector.tsx create mode 100644 client/src/components/shared/LanguageSelector/index.ts diff --git a/client/src/components/shared/LanguageSelector/LanguageSelector.module.scss b/client/src/components/shared/LanguageSelector/LanguageSelector.module.scss new file mode 100644 index 0000000000..d6bf2572a0 --- /dev/null +++ b/client/src/components/shared/LanguageSelector/LanguageSelector.module.scss @@ -0,0 +1,3 @@ +.root { + width: 12rem !important; +} diff --git a/client/src/components/shared/LanguageSelector/LanguageSelector.tsx b/client/src/components/shared/LanguageSelector/LanguageSelector.tsx new file mode 100644 index 0000000000..94dd96975c --- /dev/null +++ b/client/src/components/shared/LanguageSelector/LanguageSelector.tsx @@ -0,0 +1,40 @@ +import { TFunction } from 'i18next'; +import React, { ReactElement } from 'react'; +import { useTranslation } from 'react-i18next'; + +import InputSelect from 'components/ui/InputSelect'; +import { Option } from 'components/ui/InputSelect/types'; +import Svg from 'components/ui/Svg'; +import { earth } from 'svg/misc'; + +import styles from './LanguageSelector.module.scss'; + +const getLanguageOptions = (t: TFunction): Option[] => [ + { + label: t('languageSelector.english'), + value: 'en-EN', + }, + { + label: t('languageSelector.spanish'), + value: 'es-Es', + }, +]; + +const LanguageSelector = (): ReactElement => { + const { t, i18n } = useTranslation('translation'); + + const languageOptions = getLanguageOptions(t); + + return ( + } + onChange={option => i18n.changeLanguage(option!.value)} + options={languageOptions} + selectedOption={languageOptions.find(({ value }) => value === i18n.language)} + variant="topselect" + /> + ); +}; + +export default LanguageSelector; diff --git a/client/src/components/shared/LanguageSelector/index.ts b/client/src/components/shared/LanguageSelector/index.ts new file mode 100644 index 0000000000..8f323e3686 --- /dev/null +++ b/client/src/components/shared/LanguageSelector/index.ts @@ -0,0 +1,2 @@ +// eslint-disable-next-line no-restricted-exports +export { default } from './LanguageSelector'; diff --git a/client/src/components/shared/Layout/LayoutFooter/LayoutFooter.module.scss b/client/src/components/shared/Layout/LayoutFooter/LayoutFooter.module.scss index 00190daba7..0a5562283d 100644 --- a/client/src/components/shared/Layout/LayoutFooter/LayoutFooter.module.scss +++ b/client/src/components/shared/Layout/LayoutFooter/LayoutFooter.module.scss @@ -93,6 +93,21 @@ } } +.newsletterAndLanguageSelector { + width: 100%; + display: flex; + align-items: flex-end; +} + +.languageSelector { + height: 5.28rem; + + @media #{$phone-down} { + align-self: flex-start; + margin-top: 4rem; + } +} + .newsletterWrapper { width: 100%; display: flex; diff --git a/client/src/components/shared/Layout/LayoutFooter/LayoutFooter.tsx b/client/src/components/shared/Layout/LayoutFooter/LayoutFooter.tsx index a01c6f1bd9..b4f76c149b 100644 --- a/client/src/components/shared/Layout/LayoutFooter/LayoutFooter.tsx +++ b/client/src/components/shared/Layout/LayoutFooter/LayoutFooter.tsx @@ -1,7 +1,8 @@ import cx from 'classnames'; -import React, { FC, memo, useLayoutEffect, useRef } from 'react'; +import React, { FC, memo, ReactElement, useLayoutEffect, useRef } from 'react'; import { Trans, useTranslation } from 'react-i18next'; +import LanguageSelector from 'components/shared/LanguageSelector'; import Svg from 'components/ui/Svg'; import { BLOG_POST, @@ -22,9 +23,15 @@ import { octantSemiTransparent } from 'svg/logo'; import styles from './LayoutFooter.module.scss'; import LayoutFooterProps from './types'; +const LanguageSelectorWrapped = (): ReactElement => ( +
+ +
+); + const LayoutFooter: FC = ({ className }) => { const { t } = useTranslation('translation', { keyPrefix: 'layout.footer' }); - const { isDesktop } = useMediaQuery(); + const { isDesktop, isMobile } = useMediaQuery(); const newsletterRef = useRef(null); const dataTestRoot = 'LayoutFooter'; @@ -69,6 +76,7 @@ const LayoutFooter: FC = ({ className }) => { return (
+ {isMobile && }
@@ -112,6 +120,13 @@ const LayoutFooter: FC = ({ className }) => {
{t('newsletterText')}
+
+
+
+
{t('newsletterText')}
+
+ {!isMobile && } +
); diff --git a/client/src/components/ui/InputSelect/InputSelect.module.scss b/client/src/components/ui/InputSelect/InputSelect.module.scss index 7a5ab03904..f6dc52d7f3 100644 --- a/client/src/components/ui/InputSelect/InputSelect.module.scss +++ b/client/src/components/ui/InputSelect/InputSelect.module.scss @@ -4,7 +4,7 @@ position: relative; &.variant-- { - &underselect { + &belowselect, &topselect { width: 20rem; height: 4rem; } @@ -19,10 +19,35 @@ cursor: pointer; justify-content: space-between; + .labelWrapper { + display: flex; + align-items: center; + + .icon { + display: flex; + align-items: center; + margin-right: 0.8rem; + + &.variant-- { + &topselect { + stroke: $color-octant-grey5; + } + } + } + } + .chevron { margin: 0 1.8rem 0 1rem; width: 3.6rem; + &.variant-- { + &topselect { + path { + stroke: $color-octant-grey5; + } + } + } + &.isMenuOpen { transform: rotateX(180deg); transition: 0.3s all; @@ -37,24 +62,46 @@ padding: 0.2rem 0.8rem; } } - &underselect { + &belowselect, &topselect { $labelPaddingVertical: 0.2rem; $labelPaddingHorizontal: 1.6rem; - font-size: $font-size-12; font-weight: $font-weight-semibold; - background: $color-octant-grey8; - border-radius: $border-radius-16; - border: 0.1rem solid transparent; .label { padding: $labelPaddingVertical $labelPaddingHorizontal; + + &.hasIcon { + padding-left: 0; + } } + } + &belowselect { + background: $color-octant-grey8; + border-radius: $border-radius-16; + border: 0.1rem solid transparent; + font-size: $font-size-12; &:hover { border-color: $color-octant-grey2; } } + &topselect { + color: $color-octant-grey5; + font-size: $font-size-14; + + &:hover { + color: $color-octant-grey13; + + .icon { + stroke: $color-octant-grey13; + } + + .chevron path { + stroke: $color-octant-grey13; + } + } + } } } @@ -62,7 +109,12 @@ position: absolute; @media #{$tablet-down} { - @include overlay(100%, 100%); + &.isVariantFullWidthOnMobile { + @include overlay(100%, 100%, true); + } + &:not(.isVariantFullWidthOnMobile) { + @include overlay(100%, 100%, false); + } } } @@ -72,7 +124,6 @@ bottom: 0; right: 0; margin: 0; - padding: 2.4rem 0; border-radius: $border-radius-16; z-index: $z-index-6; box-shadow: $box-shadow-1; @@ -80,19 +131,36 @@ width: 100%; background: $color-white; - @media #{$desktop-up} { - position: absolute; - width: 12.8rem; - padding: 1.6rem 0; - bottom: auto; + &.variant-- { + &topselect { + position: absolute; + width: 14.4rem; + bottom: 100%; + left: 50%; + transform: translate(-50%) !important; + padding: 0.8rem 0; + } + &overselect, &belowselect { + padding: 2.4rem 0; + } + } + + @media #{$desktop-up} { &.variant-- { + &overselect, &underselect { + position: absolute; + width: 12.8rem; + padding: 1.6rem 0; + bottom: auto; + } + &overselect { top: -2rem; right: -0.73rem; } - &underselect { + &belowselect { width: 100%; top: 5rem; } @@ -128,9 +196,13 @@ } @media #{$desktop-up} { - font-size: $font-size-12; - height: 3.2rem; - padding-left: 0; + &.variant-- { + &belowselect, &overselect { + font-size: $font-size-12; + height: 3.2rem; + padding-left: 0; + } + } } &:hover { @@ -138,7 +210,11 @@ } &.variant-- { - &overselect { + &topselect { + font-size: $font-size-14; + } + + &topselect, &overselect { .iconTick { left: 2.5rem; } @@ -147,7 +223,7 @@ justify-content: center; } } - &underselect { + &belowselect { flex-direction: row-reverse; padding: 0 5.6rem; diff --git a/client/src/components/ui/InputSelect/InputSelect.tsx b/client/src/components/ui/InputSelect/InputSelect.tsx index 9d3a10e4af..aa5cd8413d 100644 --- a/client/src/components/ui/InputSelect/InputSelect.tsx +++ b/client/src/components/ui/InputSelect/InputSelect.tsx @@ -17,6 +17,7 @@ const durationOfTransitionMobile = 0.3; const InputSelect: FC = ({ className, dataTest = 'InputSelect', + Icon, options, onChange, selectedOption, @@ -70,6 +71,8 @@ const InputSelect: FC = ({ return () => document.removeEventListener('click', listener); }, [isMenuOpen, isDesktop]); + const isVariantFullWidthOnMobile = ['overselect', 'belowselect'].includes(variant); + return (
= ({ onClick={() => setIsMenuOpen(prev => !prev)} >
- - {_selectedOption?.label} - +
+ {Icon &&
{Icon}
} + + {_selectedOption?.label} + +
@@ -93,7 +106,11 @@ const InputSelect: FC = ({ { @@ -124,12 +141,14 @@ const InputSelect: FC = ({ duration: durationOfTransition, }} > -
-
-
- {t('newsletterText')} -
From 615d1a540f53063167b366e32f47dee05305c8af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Zi=C3=B3=C5=82ek?= Date: Mon, 2 Dec 2024 09:56:54 +0100 Subject: [PATCH 07/12] style: LanguageSelectorWrapped extracted into separate component --- .../LanguageSelectorWrapped.module.scss | 3 +++ .../LanguageSelectorWrapped.tsx | 15 +++++++++++++++ .../Layout/LanguageSelectorWrapped/index.ts | 2 ++ .../Layout/LanguageSelectorWrapped/types.ts | 3 +++ .../Layout/LayoutFooter/LayoutFooter.module.scss | 2 -- .../shared/Layout/LayoutFooter/LayoutFooter.tsx | 10 ++-------- 6 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 client/src/components/shared/Layout/LanguageSelectorWrapped/LanguageSelectorWrapped.module.scss create mode 100644 client/src/components/shared/Layout/LanguageSelectorWrapped/LanguageSelectorWrapped.tsx create mode 100644 client/src/components/shared/Layout/LanguageSelectorWrapped/index.ts create mode 100644 client/src/components/shared/Layout/LanguageSelectorWrapped/types.ts diff --git a/client/src/components/shared/Layout/LanguageSelectorWrapped/LanguageSelectorWrapped.module.scss b/client/src/components/shared/Layout/LanguageSelectorWrapped/LanguageSelectorWrapped.module.scss new file mode 100644 index 0000000000..e3e7c9f173 --- /dev/null +++ b/client/src/components/shared/Layout/LanguageSelectorWrapped/LanguageSelectorWrapped.module.scss @@ -0,0 +1,3 @@ +.root { + height: 5.28rem; +} diff --git a/client/src/components/shared/Layout/LanguageSelectorWrapped/LanguageSelectorWrapped.tsx b/client/src/components/shared/Layout/LanguageSelectorWrapped/LanguageSelectorWrapped.tsx new file mode 100644 index 0000000000..f92f7a0ac5 --- /dev/null +++ b/client/src/components/shared/Layout/LanguageSelectorWrapped/LanguageSelectorWrapped.tsx @@ -0,0 +1,15 @@ +import cx from 'classnames'; +import React, { FC } from 'react'; + +import LanguageSelector from 'components/shared/LanguageSelector'; + +import styles from './LanguageSelectorWrapped.module.scss'; +import LanguageSelectorWrappedProps from './types'; + +const LanguageSelectorWrapped: FC = ({ className }) => ( +
+ +
+); + +export default LanguageSelectorWrapped; diff --git a/client/src/components/shared/Layout/LanguageSelectorWrapped/index.ts b/client/src/components/shared/Layout/LanguageSelectorWrapped/index.ts new file mode 100644 index 0000000000..f69a6a5546 --- /dev/null +++ b/client/src/components/shared/Layout/LanguageSelectorWrapped/index.ts @@ -0,0 +1,2 @@ +// eslint-disable-next-line no-restricted-exports +export { default } from './LanguageSelectorWrapped'; diff --git a/client/src/components/shared/Layout/LanguageSelectorWrapped/types.ts b/client/src/components/shared/Layout/LanguageSelectorWrapped/types.ts new file mode 100644 index 0000000000..335badf236 --- /dev/null +++ b/client/src/components/shared/Layout/LanguageSelectorWrapped/types.ts @@ -0,0 +1,3 @@ +export default interface LanguageSelectorWrappedProps { + className?: string; +} diff --git a/client/src/components/shared/Layout/LayoutFooter/LayoutFooter.module.scss b/client/src/components/shared/Layout/LayoutFooter/LayoutFooter.module.scss index 0a5562283d..191968f4b3 100644 --- a/client/src/components/shared/Layout/LayoutFooter/LayoutFooter.module.scss +++ b/client/src/components/shared/Layout/LayoutFooter/LayoutFooter.module.scss @@ -100,8 +100,6 @@ } .languageSelector { - height: 5.28rem; - @media #{$phone-down} { align-self: flex-start; margin-top: 4rem; diff --git a/client/src/components/shared/Layout/LayoutFooter/LayoutFooter.tsx b/client/src/components/shared/Layout/LayoutFooter/LayoutFooter.tsx index 527c46344c..1070dd50ce 100644 --- a/client/src/components/shared/Layout/LayoutFooter/LayoutFooter.tsx +++ b/client/src/components/shared/Layout/LayoutFooter/LayoutFooter.tsx @@ -1,8 +1,8 @@ import cx from 'classnames'; -import React, { FC, memo, ReactElement, useLayoutEffect, useRef } from 'react'; +import React, { FC, memo, useLayoutEffect, useRef } from 'react'; import { Trans, useTranslation } from 'react-i18next'; -import LanguageSelector from 'components/shared/LanguageSelector'; +import LanguageSelectorWrapped from 'components/shared/Layout/LanguageSelectorWrapped'; import Svg from 'components/ui/Svg'; import { BLOG_POST, @@ -23,12 +23,6 @@ import { octantSemiTransparent } from 'svg/logo'; import styles from './LayoutFooter.module.scss'; import LayoutFooterProps from './types'; -const LanguageSelectorWrapped = (): ReactElement => ( -
- -
-); - const LayoutFooter: FC = ({ className }) => { const { t } = useTranslation('translation', { keyPrefix: 'layout.footer' }); const { isDesktop, isMobile } = useMediaQuery(); From 309ee15566e1aa6ce38ec969bcd847e1aedba397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Zi=C3=B3=C5=82ek?= Date: Thu, 5 Dec 2024 10:29:39 +0100 Subject: [PATCH 08/12] fix: underselect instead of belowselect class name --- client/src/components/ui/InputSelect/InputSelect.module.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/ui/InputSelect/InputSelect.module.scss b/client/src/components/ui/InputSelect/InputSelect.module.scss index f6dc52d7f3..9175a66773 100644 --- a/client/src/components/ui/InputSelect/InputSelect.module.scss +++ b/client/src/components/ui/InputSelect/InputSelect.module.scss @@ -148,7 +148,7 @@ @media #{$desktop-up} { &.variant-- { - &overselect, &underselect { + &overselect, &belowselect { position: absolute; width: 12.8rem; padding: 1.6rem 0; From 742bfe1bc60294fb702771b4dfe0168002e1759e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Zi=C3=B3=C5=82ek?= Date: Fri, 6 Dec 2024 13:07:17 +0100 Subject: [PATCH 09/12] feat: new translations --- client/src/locales/es/translation.json | 282 ++++++++++++------------- 1 file changed, 141 insertions(+), 141 deletions(-) diff --git a/client/src/locales/es/translation.json b/client/src/locales/es/translation.json index 2f4d7c0d39..b476f3f1fb 100644 --- a/client/src/locales/es/translation.json +++ b/client/src/locales/es/translation.json @@ -2,30 +2,30 @@ "api": { "errorMessage": { "allocations": { - "allocateAboveRewardsBudget": "No tienes tanto en tu presupuesto de recompensas. Vuelve a intentarlo cuando hayas ganado más recompensas.", + "allocateAboveRewardsBudget": "Aún no tienes el suficiente presupuesto de recompensas. Vuelve a intentarlo cuando hayas ganado más recompensas.", "decisionWindowClosed": "El período de adjudicación no está abierto en este momento. Inténtelo nuevamente más tarde.", - "notStartedYet": "La época aún no ha comenzado. Inténtalo de nuevo más tarde." + "notStartedYet": "La época aún no ha comenzado. Inténtalo más tarde." }, "deposits": { - "cannotTransferFromSender": "Se produjo un error con la transferencia de GLM, pero tus fondos están seguros. Vuelve a intentarlo.", - "depositIsSmaller": "No hay fondos suficientes" + "cannotTransferFromSender": "Se produjo un error con la transferencia de tokens GLM, pero tus fondos están seguros. Vuelve a intentarlo.", + "depositIsSmaller": "Fondos insuficientes." }, "history": { "loadingEncounteredAnError": "Se ha producido un problema al cargar el historial de operaciones. Inténtalo de nuevo." }, - "userRejectedWalletOperation": "El usuario rechazó la operación de billetera", + "userRejectedWalletOperation": "El usuario rechazó la operación de la billetera", "default": { "title": "Lo siento, algo salió mal allí.", - "message": "Por favor, recarga la aplicación y vuelve a intentarlo." + "message": "Por favor, actualiza nuevamente la aplicación y vuelve a intentarlo." }, "ipfs": { - "message": "Parece que tenemos problemas para cargar datos desde IPFS, espere o intente recargar" + "message": "Parece que tenemos problemas para cargar datos desde IPFS, espera o intenta actualizar la página" } } }, "common": { "availableNow": "Disponible ahora", - "close": "Cerca", + "close": "Cerrar", "closes": "Cierra", "copied": "Copiado", "copy": "Copiar enlace", @@ -33,12 +33,12 @@ "donations": "Donaciones", "done": "Hecho", "gettingStarted": "Empezando", - "lockGlm": "Bloqueo GLM", + "lockGlm": "Bloquea tus GLM", "personal": "Personal", "personalAllocation": "Asignación personal", "projectForbiddenOperation": "Como proyecto no puedes continuar con esta operación", "rewards": "Recompensas {{rewards}}", - "matchFunding": "Financiación de contrapartida", + "matchFunding": "Financiación equiparada", "valueCantBeEmpty": "El valor no puede estar vacío", "lessThan1m": "Menos de 1 m", "donors": "Donantes", @@ -53,38 +53,38 @@ "lockedGLM": "GLM bloqueado", "unlockedGLM": "GLM desbloqueado", "total": "Total", - "matching": "Pareo", + "matching": "Coincidencia", "confirmed": "Confirmado" }, "components": { "allocation": { - "emptyState": "Bloquee algunos GLM para ganar recompensas, luego agregue proyectos aquí desde la vista de para donarlos durante la ventana de Asignación", - "emptyStateAWOpen": "Visita la <0>vista Proyectos<\/0> para agregar tus proyectos favoritos y así poder donarles recompensas aquí", - "emptyStateMobile": "Bloquee algunos GLM para ganar recompensas, luego agregue proyectos aquí desde la vista Proyectos para donarlos durante la ventana de Asignación", - "emptyStateMobileAWOpen": "Visita la <0>vista Proyectos<\/0> para agregar tus proyectos favoritos y así poder donarles recompensas aquí", - "allocateRewards": "Asignar recompensas", + "emptyState": "Bloquee algunos GLM para ganar recompensas, luego agrega proyectos aquí desde la vista de
para donarlos durante la ventana de Asignación", + "emptyStateAWOpen": "Visita la <0>vista Proyectos para agregar tus proyectos favoritos
y donarles recompensas aquí", + "emptyStateMobile": "Bloquea algunos tokens GLM para ganar recompensas,
luego agrega proyectos aquí desde la vista Proyectos
para donarlos durante la ventana de Asignación", + "emptyStateMobileAWOpen": "Visita la <0>vista Proyectos para agregar tus proyectos
favoritos y así poder donarles recompensas aquí", + "allocateRewards": "Asigna tus recompensas", "lowUQScoreModal": { - "header": "Su puntuación UQ es inferior a 15", - "text": "Una puntuación de Gitcoin Passport de 15 o más multiplicará por 10 la financiación de tu donación. Para aumentar tu puntuación, visita el panel de control de GP personalizado que aparece a continuación para agregar más sellos antes de realizar la asignación.", + "header": "Tu puntuación UQ es inferior a 15", + "text": "Una puntuación de Gitcoin Passport de 15 o más multiplicará por 10 la financiación de tu donación. Para aumentar tu puntuación, visita el panel de control de GP personalizado que aparece a continuación para agregar más sellos antes de hacer la asignación.", "checkboxLabel": "Entiendo que solo recibiré el 10% del financiamiento máximo equivalente.", "goToGitcoinPassportCustomOctantDashboard": "Ir al panel de control de GP", "proceedToAllocate": "Asignar de todos modos", "toasts": { "success": { - "title": "Aumentaste con éxito tu puntuación UQ", - "message": "Ahora tienes a tu disposición un apalancamiento completo" + "title": "Has aumentado exitosamente tu puntuación UQ", + "message": "Ahora tienes acceso al apalancamiento completo de equiparación" } } }, "multisigSignatureToast": { "title": "Multi-sig: se necesita firma", - "message": "Se requiere al menos una firma para iniciar la asignación. No cierre Octant." + "message": "Se requiere al menos una firma para iniciar la asignación. Por favor, no cierres la ventana de Octant." }, "allocationItem": { "epoch1": "No hay umbral de financiación en la época 1", - "standard": "{{sum}} \/ {{threshold}}", + "standard": "{{sum}} / {{threshold}}", "simulate": "Tu impacto {{value}}", - "simulateLoading": "Calculador..." + "simulateLoading": "Calculando..." } }, "shared": { @@ -97,21 +97,21 @@ "currentRewards": "Recompensas actuales", "currentDonations": "Donaciones actuales", "totalRewards": "Recompensas totales", - "currentMatchFunding": "Financiación actual de contrapartida", + "currentMatchFunding": "Financiación actual", "rewardsRate": "Tasa de recompensas", - "rewardsRateTooltip": "La tasa de recompensas es el porcentaje de tu GLM bloqueado que ganas como recompensas por época.", - "epochTotalMatchFunding": "Financiación total de Epoch", + "rewardsRateTooltip": "La tasa de recompensas es el porcentaje de tus tokens GLM bloqueados que ganas como recompensas por cada época.", + "epochTotalMatchFunding": "Financiación total de la época", "epochMF": "Época MF" }, "homeGridVideoBar": { - "learnHowToUseOctant": "Aprenda a utilizar Octant", - "closeVideoWithArrow": "Cerrar video ->" + "learnHowToUseOctant": "Aprende a usar Octant", + "closeVideoWithArrow": "Cerrar vídeo ->" }, "homeGridCurrentGlmLock": { "currentGlmLock": "Bloqueo GLM actual", "editLockedGLM": "Editar GLM bloqueado", - "effective": "Eficaz", - "tooltipText": "El bloqueo efectivo (EL) es la parte de tu GLM bloqueado que actualmente genera recompensas. Si bloqueas más, el EL aumenta proporcionalmente al tiempo de época restante. Si desbloqueas el GLM, esa cantidad se eliminará del EL para la época. Ten en cuenta que si el EL cae por debajo de 100, no se calcularán recompensas.", + "effective": "Efectivo", + "tooltipText": "El bloqueo efectivo (EL) es la parte de tus tokens GLM bloqueados que actualmente genera recompensas. Si bloqueas más, el EL aumenta proporcionalmente al tiempo de época restante. Si desbloqueas el GLM, esa cantidad se eliminará del EL para la época. Ten en cuenta que si el EL cae por debajo de 100, no podrás calcular tus recompensas.", "modalLockGlm": { "unlockGLM": "Desbloquear GLM", "lockGlmBudgetBox": { @@ -120,36 +120,36 @@ "walletBalance": "Saldo de la billetera", "raffleWinnings": { "oneWin": "Bloqueado hasta {{date}}", - "multipleWins": "Ganancias bloqueadas en el tiempo" + "multipleWins": "Ganancias con bloqueo temporal" } } }, "raffleWinnerBadge": { "text": "{{value}} ganancias de GLM", - "tooltipWinningRow": "{{value}} premio bloqueado hasta {{date}}", + "tooltipWinningRow": "{{value}} recompensa bloqueada hasta el {{date}}", "tooltipCurrentBalanceRow": "{{value}} tu saldo bloqueado" } }, "homeGridPersonalAllocation": { - "yourFunds": "Sus fondos", + "yourFunds": "Tus fondos", "withdrawToWallet": "Retirar a la billetera", - "pendingFundsAvailableAfter": "Fondos pendientes disponibles después de", + "pendingFundsAvailableAfter": "Fondos pendientes disponibles a partir de", "modalWithdrawEth": { "withdrawETH": "Retirar ETH", "estimatedGasPrice": "Precio estimado del gas", - "withdrawAll": "Retirar todo" + "withdrawAll": "Retirarlo todo" } }, "homeGridUQScore": { "yourUniquenessScore": "Tu puntuación de singularidad", - "isOnTimeOutListLabel": "Cuenta de Sybil", + "isOnTimeOutListLabel": "Cuenta Sybil", "recalculate": "Recalcular", "delegate": "Delegar", "whatIsThis": "¿Qué es esto?", - "scoreTooLow": "¿La puntuación es demasiado baja? Visite el panel de control de Octant Passport", - "wantToDispute": "¿Quieres disputar la condición de Sybil? Utiliza este formulario", + "scoreTooLow": "¿Puntuación muy baja? Visita el panel de control de Octant Passport", + "wantToDispute": "¿Quieres disputar el estado Sybil de tu cuenta? Usa este formulario:", "addresses": "direcciones", - "primary": "Primario", + "primary": "Principal", "noWalletConnected": "No hay billetera conectada", "addressScore": { "signMessage": "Firmar mensaje" @@ -157,24 +157,24 @@ "progressPath": { "checkingPassportScore": "Comprobación de la puntuación del pasaporte", "finished": "Finalizado", - "checkingAllowlist": "Comprobando lista de permitidos" + "checkingAllowlist": "Verificando lista de permitidos" }, "modalCalculatingYourUniqueness": { "calculatingYourUniqueness": "Calculando tu singularidad", - "calculatingYourUniquenessStep1": "Para demostrar tu singularidad, necesitas una puntuación de <0>Gitcoin Passport<\/0> de 15 o más. Si la tienes, tus donaciones atraerán la cantidad máxima de financiación equivalente. De lo contrario, la financiación equivalente máxima se establecerá en el 10 %. Puedes aumentar tu puntuación de un par de formas diferentes.", - "calculatingYourUniquenessStep2": "Puede ir a nuestro <0>panel de Passport<\/0> y agregar sellos al puntaje de su dirección Octant. Si su puntaje Passport no está en su dirección principal, puede delegar su puntaje desde otra dirección con un puntaje Passport de 15 o más. Solo puede hacer esto una vez y debe hacerse antes de asignar para beneficiar la época actual.", - "calculatingYourUniquenessStep3": "La delegación no vinculará sus direcciones ni comprometerá su privacidad de ninguna manera. Requerimos una prueba de unicidad para defendernos contra los ataques de Sybil, ya que hemos cambiado a un modelo de financiación cuadrático. Para obtener más información, consulte la práctica <0>guía de Gitcoin para mejorar su puntuación.<\/0>" + "calculatingYourUniquenessStep1": "Para demostrar tu singularidad, necesitas una puntuación del <0>Gitcoin Passport de 15 o más.

Si la tienes, tus donaciones atraerán la cantidad máxima de financiación equivalente. De lo contrario, la financiación equivalente máxima se establecerá en el 10 %.

Puedes aumentar tu puntuación de formas diferentes.", + "calculatingYourUniquenessStep2": "Puedes ir a nuestro <0>panel del Pasaporte y agregar sellos al puntaje de tu dirección Octant.

Si su puntaje Passport no está en su dirección principal, puede delegar su puntaje desde otra dirección con un puntaje Passport de 15 o más.

Solo puedes hacer esto una vez y debe hacerse antes de asignar para beneficiar la época actual.", + "calculatingYourUniquenessStep3": "La delegación no vinculará sus direcciones ni comprometerá su privacidad de ninguna manera.

Requerimos una prueba de singularidad para poder protegernos en contra los ataques Sybil, ya que hemos cambiado a un modelo de financiación cuadrático.

Para obtener más información, consulta la práctica <0>guía de Gitcoin para mejorar tu puntuación." }, "modalCalculatingUQScore": { - "signMessages": "Mensajes de firma", + "signMessages": "Firmar mensajes", "switchAccount": "Cambiar de cuenta", "calculatingScore": "Calcular puntuación", - "delegationFailedText": "La delegación falló: su puntuación debe ser 15 o superior. Intente con otra dirección", + "delegationFailedText": "La delegación falló: su puntuación debe ser 15 o superior. Intente con otra billetera", "delegationMessageToSign": "Delegación de la puntuación UQ de {{delegationSecondaryAddress}} a {{delegationPrimaryAddress}}", "toasts": { "unableToDelegateToAddressWithPositiveGLMLock": { - "title": "Dirección con GLM bloqueada", - "message": "Por favor delegar a una dirección sin GLM bloqueado" + "title": "Dirección con tokens GLM bloqueados", + "message": "Por favor delega a una billetera sin tokens GLM bloqueados" } } }, @@ -184,26 +184,26 @@ "toasts": { "delegationTooManyUniqueAddresses": { "title": "Demasiadas cuentas", - "message": "Conecte hasta 10 cuentas para verificar el estado de su delegación" + "message": "Conecta hasta 10 cuentas para verificar el estado de tu delegación" } } }, "homeGridRewardsEstimator": { "rewardsEstimator": "Calculadora de recompensas", - "enterGLMAmount": "Introduzca un importe GLM", - "lockForEpoch_one": "Bloqueo por {{count}} época", - "lockForEpoch_other": "Bloqueo por {{count}} épocas", + "enterGLMAmount": "Introduce una cantidad de tokens GLM", + "lockForEpoch_one": "Bloquear por {{count}} época", + "lockForEpoch_other": "Bloquear por {{count}} épocas", "minimalUqValueGivingMultiplier1": "UQ 15+", "errors": { - "valueCryptoTooBig": "Esa no es una cantidad válida" + "valueCryptoTooBig": "La cantidad no es válida" } }, "homeGridTransactions": { - "transactions": "Actas", + "transactions": "Transacciones", "modalTransactionDetails": { "header": { - "allocation": "Asignaciones de época {{epoch}}", - "withdrawal": "Retiré ETH" + "allocation": "Asignaciones de la época {{epoch}}", + "withdrawal": "Retira ETH" }, "sections": { "allocationProjects": "Proyectos ( {{projectsNumber}} )", @@ -212,17 +212,17 @@ "estimatedLeverage": "Apalancamiento estimado", "finalMatchFunding": "Financiación del partido final", "when": "Cuando", - "matchingFundDonation": "Donación de fondos de contrapartida", + "matchingFundDonation": "Donación de financiación equiparada", "leverageUnknown": "Desconocido", "allocationTooltips": { "leverageUnknown": "No conocemos el apalancamiento de esta asignación pasada.", "finalMatchFunding": "Una vez finalizado el período de asignación, sabemos el monto exacto de la financiación equivalente que atrajo su donación, por lo que mostramos eso en lugar de solo el monto de apalancamiento estimado.", - "leverage": "El apalancamiento muestra el múltiplo de su donación que los proyectos que usted eligió recibirán en concepto de financiación equivalente. Tenga en cuenta que puede cambiar drásticamente durante un período y ser muy diferente de la financiación equivalente final." + "leverage": "El apalancamiento muestra el múltiplo de su donación que los proyectos que usted eligió recibirán en concepto de financiación equivalente. Ten en cuenta que puede cambiar drásticamente durante la época y ser muy diferente de la financiación equivalente final." } } }, "transactionsList": { - "empty": "Aún no hay historial de transacciones. Bloquee algunos GLM para comenzar" + "empty": "No hay historial de transacciones todavía.
Bloquea algunos tokens GLM para empezar" }, "transactionsListItem": { "allocatedRewards": "Recompensas asignadas", @@ -230,13 +230,13 @@ "epochDonation": "Donación de Epoch {{epoch}}" }, "transactionLabel": { - "pendingMultisig": "Pendiente multifirma" + "pendingMultisig": "Pendiente de la multifirma" } }, "homeGridDonations": { "donationHistory": "Historial de donaciones", - "noDonationsYet": "Aún no hay donaciones. Bloquea y gana recompensas por donar", - "noDonationsYetAWOpen": "Consulte la <0>vista Proyectos<\/0> para encontrar proyectos para financiar" + "noDonationsYet": "Aún no hay donaciones. Bloquea tokens GLM
y gana recompensas por donar", + "noDonationsYetAWOpen": "Consulte la <0>vista Proyectos
para encontrar proyectos para financiar" }, "homeGridEpochResults": { "epochResults": "Resultados de Época {{epoch}}", @@ -244,9 +244,9 @@ "donationsShort": "D", "matchingShort": "M", "totalShort": "T", - "clickToVisitProject": "Haga clic para visitar el proyecto", + "clickToVisitProject": "Haz clic para visitar el proyecto", "loadingChartData": "Cargando datos del gráfico ", - "scrollInfo": "Haga clic y arrastre o desplácese para ver más proyectos", + "scrollInfo": "Haz clic y arrastra o desplázate para ver más proyectos", "scrollInfoMobile": "Toque y arrastre para ver más proyectos" } }, @@ -256,30 +256,30 @@ "enablePatronMode": "Habilitar modo mecenas", "disablePatronMode": "Deshabilitar el modo mecenas", "patronModeSignatureMessage": "Al firmar este mensaje se {{state}} el modo de usuario para la dirección {{address}}.", - "firstParagraph": "Este modo es para los poseedores de tokens
que desean apoyar a Octant.", + "firstParagraph": "Este modo es para los poseedores de tokens
que desean apoyar a Octant.", "secondParagraph": "Deshabilita y elimina todas las asignaciones personales y donaciones a proyectos.", - "thirdParagraph": "Todas las recompensas se destinan directamente al fondo de contrapartida sin que el patrocinador deba realizar ninguna acción. Obtenga más información en <0>Documentación<\/0>.", - "fourthParagraphEnable": "Deslice el interruptor que se encuentra debajo completamente hacia la
para habilitar el modo usuario.", - "fourthParagraphDisable": "Deslice el interruptor que se encuentra
completamente hacia la izquierda para desactivar el modo usuario.", + "thirdParagraph": "Todas las recompensas se destinan directamente al fondo de contrapartida sin que el patrocinador deba realizar ninguna acción. Obtenga más información en <0>Documentación.", + "fourthParagraphEnable": "Desliza el interruptor que se encuentra debajo completamente hacia la derecha
para habilitar el modo usuario.", + "fourthParagraphDisable": "Deslice el interruptor que se encuentra
completamente hacia la izquierda para desactivar el modo usuario.", "patronModeEnabled": "Modo mecenas habilitado", "patronModeDisabled": "Modo de usuario deshabilitado", - "slideRightToConfirm": "Deslice hacia la derecha para confirmar", - "slideLeftToConfirm": "Deslice hacia la izquierda para confirmar" + "slideRightToConfirm": "Desliza hacia la derecha para confirmar", + "slideLeftToConfirm": "Desliza hacia la izquierda para confirmar" } }, "dedicated": { "buttonAddToAllocate": { - "saveToAllocate": "Guardar para asignar", + "saveToAllocate": "Guardar para la asignación", "saved": "Guardado", "removeFromAllocate": "Quitar de la asignación", - "removed": "Remoto", + "removed": "Eliminado", "saveProject": "Guardar proyecto", "savedProject": "Proyecto guardado" }, "allocationNavigation": { "confirm": "Confirmar", "reset": "Reiniciar", - "waiting": "Espera" + "waiting": "Esperando" }, "allocationRewardsBox": { "subtitleNoRewards": "Aún no hay recompensas", @@ -287,8 +287,8 @@ "donateWithPercentage": "Donar {{percentage}} %", "personalWithPercentage": "{{percentage}} %", "allocated": "Asignado", - "manual": "Manual", - "availableDuringAllocation": "Disponible durante la asignación" + "manual": "Ajuste manual", + "availableDuringAllocation": "Disponible durante el período de asignación" }, "allocationSummary": { "totalImpact": "Impacto total", @@ -296,29 +296,29 @@ "allocationProjects": "Proyectos ( {{projectsNumber}} )" }, "connectWallet": { - "browserWallet": "Monedero del navegador", + "browserWallet": "Billetera del navegador", "connecting": "Conectando...", "walletConnect": "Conexión de billetera", - "ledgerConnect": "Libro mayor" + "ledgerConnect": "Conexión con Ledger" }, "glmLock": { "lock": "Cerrar", - "unlock": "Descubrir", + "unlock": "Desbloquear", "glmLockStepper": { "approve": "Aprobar" }, "glmLockTabs": { - "useMax": "Utilice el máximo", - "amountToLock": "Cantidad a bloquear", - "amountToUnlock": "Cantidad a desbloquear", + "useMax": "Utilizar el máximo", + "amountToLock": "Cantidad para bloquear", + "amountToUnlock": "Cantidad para desbloquear", "locked": "Bloqueado", - "timeLocked": "Tiempo bloqueado" + "timeLocked": "Bloqueado por tiempo" }, "glmLockNotification": { "success": { "labelLocked": "GLM bloqueado exitosamente", "labelUnlocked": "GLM desbloqueado exitosamente", - "text": "Su saldo bloqueado se actualizará después de la confirmación de la transacción. <0>Ver en Etherscan<\/0>" + "text": "Tu saldo bloqueado se actualizará después de la confirmación de la transacción. <0>Ver en Etherscan" }, "info": { "lock": { @@ -331,12 +331,12 @@ } }, "modalConnectWallet": { - "connectVia": "Conectarse a través de" + "connectVia": "Conectar mediante" }, "projectRewards": { "epoch": "Época {{epoch}}", "currentTotal": "Total actual", - "totalRaised": "Total recaudado", + "totalRaised": "Fondos totales recaudados", "fundedIn": "Financiado en", "fundedAt": "Financiado en", "didNotReach": "No llegó", @@ -348,18 +348,18 @@ }, "projectsSearchResults": { "searchResultsLabel": "Época {{epochNumber}}", - "noSearchResults": "No hubo suerte, por favor inténtalo de nuevo" + "noSearchResults": "No encontramos resultados, por favor inténtalo de nuevo" }, "timeCounter": { "hours": "Horas", "minutes": "Minutos", - "seconds": "Artículos de segunda clase" + "seconds": "Segundos" }, "tos": { - "text": "Acepto los <0>Términos de servicio<\/0>" + "text": "Acepto los <0>Términos de servicio" }, "walletModal": { - "balances": "Saldos", + "balances": "Saldo", "wallet": "Billetera", "disconnectWallet": "Desconectar la billetera" } @@ -367,7 +367,7 @@ }, "layout": { "navigationTabs": { - "home": "Hogar", + "home": "Inicio", "metrics": "Métrica", "settings": "Ajustes", "allocate": "Asignar" @@ -375,9 +375,9 @@ "topBar": { "epochAllocationOpensIn": "La asignación de época {{epoch}} se abre en {{duration}}", "epochAllocationOpensInShort": "{{duration}} hasta la asignación", - "epochAllocationClosesIn": "La asignación de la época {{epoch}} cierra en {{duration}}", + "epochAllocationClosesIn": "La asignación de la época {{epoch}} se cierra en {{duration}}", "epochAllocationClosesInShort": "La asignación se cierra en {{duration}}", - "epochAllocationWindowOpen": "La ventana de asignación de época {{epoch}} está abierta", + "epochAllocationWindowOpen": "La ventana de asignación de la época {{epoch}} está abierta", "epochAllocationWindowOpenShort": "¡Asignar ahora!", "connectWallet": "Conectar billetera", "connect": "Conectar", @@ -388,29 +388,29 @@ "days_other": "días", "hours_one": "hora", "hours_other": "horas", - "hoursShort": "yo", + "hoursShort": "h", "minutes_one": "minuto", "minutes_other": "minutos", "minutesShort": "mín." }, "footer": { - "newsletterText": "Reciba noticias y actualizaciones de PGF de Octant. Sin spam, nunca", - "octantText": "Octant es un proyecto de la <0>Fundación Golem<\/0>, lanzado en 2023.", + "newsletterText": "Recibe noticias y actualizaciones de PGF de Octant. Nunca enviaremos spam", + "octantText": "Octant es un proyecto de la <0>Fundación Golem,
lanzado en 2023.", "links": { "website": "Sitio web", "discord": "Discordia", "blog": "Blog", "docs": "Documentos", - "brandAssets": "Activos de marca", + "brandAssets": "Activos de la marca", "termsOfUse": "Condiciones de uso", - "farcaster": "Teleyector", - "twitterX": "Gorjeo\/X", + "farcaster": "Farcaster", + "twitterX": "Twitter/X", "privacyPolicy": "Política de privacidad" } } }, "meta": { - "description": "Octant es una plataforma que permite a los usuarios bloquear GLM, ganar recompensas ETH y financiar proyectos que les interesan.", + "description": "Octant es una plataforma que permite a los usuarios bloquear tokens GLM, ganar recompensas en ETH y financiar proyectos que les interesan.", "fundrasingOnOctant": "{{projectName}} está recaudando fondos en Octant" }, "toasts": { @@ -425,10 +425,10 @@ "views": { "home": { "title": { - "isDecisionWindowOpenFalse": "Bienvenido a Epoch {{epoch}}", + "isDecisionWindowOpenFalse": "Bienvenido al Epoch {{epoch}}", "isDecisionWindowOpenTrue": { - "desktop": "Bienvenido a la ventana de asignación de Epoch {{epoch}}", - "mobile": "Bienvenido a E {{epoch}} AW" + "desktop": "Bienvenido a la ventana de asignación del Epoch {{epoch}}", + "mobile": "Bienvenido al E {{epoch}} AW" } } }, @@ -442,47 +442,47 @@ "epoch": "Época", "epochAllocationWindow": "Ventana de asignación de época {{epoch}}", "epochAllocation": "Asignación de E {{epoch}}", - "generalMetrics": "Métricas generales", + "generalMetrics": "Estadísticas generales", "donationsVsPersonal": "Donaciones vs. personales", - "donationsVsMatchFunding": "Donaciones vs. fondos de contrapartida", - "totalMatching": "Coincidencia total", + "donationsVsMatchFunding": "Donaciones vs financiación equiparada", + "totalMatching": "Total de financiación equiparada", "totalProjects": "Proyectos totales", "totalEthStaked": "Total de ETH en staking", - "totalGlmLocked": "GLM total bloqueado", + "totalGlmLocked": "Total de GLM bloqueado", "of1BTotalSupply": "de 1B de suministro total", - "cumulativeGlmLocked": "GLM acumulado bloqueado", + "cumulativeGlmLocked": "GLM bloqueado acumulado", "walletsWithGlmLocked": "Monederos con GLM bloqueado", "totalProjectsSinceEpoch0": "{{projectsAmount}} total desde E0", "belowThreshold": "Por debajo del umbral", "ethBelowThreshold": "ETH por debajo del umbral", "totalDonations": "Donaciones totales", - "averageLeverage": "Apalancamiento medio", + "averageLeverage": "Apalancamiento promedio", "currentDonors": "Donantes actuales", "patrons": "Patrocinadores", - "rewardsUnused": "Recompensas no utilizadas", + "rewardsUnused": "Recompensas sin utilizar", "unallocatedValue": "Valor no asignado", "users": "Usuarios", "totalUsers": "Usuarios totales", - "fundsUsage": "Uso de fondos de Epoch {{epoch}} ", + "fundsUsage": "Uso de fondos de la época {{epoch}} ", "epochTotal": "Época {{epoch}} Total", "leftover": "Movido a E {{epochNumber}}", - "staking": "Estaca", - "communityFund": "Fondo comunitario", + "staking": "Bloqueado", + "communityFund": "Fondo Comunitario", "ppf": "PPF", "projectCosts": "Costos del proyecto" }, "onboarding": { "modalTimeoutListPresence": { - "header": "Esta cuenta parece una sibila", - "text": "Hemos marcado esta cuenta como <0>sybil<\/0>, lo que significa que su asignación no recibirá fondos equivalentes en esta época. Si desea impugnar esto, <1>complete este formulario<\/1> y lo revisaremos.", - "checkboxLabel": "Entiendo que no recibiré fondos equivalentes en esta época.", + "header": "Esta cuenta parece sybil", + "text": "Hemos marcado esta cuenta como <0>sybil, lo que significa que tu asignación no recibirá fondos equivalentes en esta época. Si deseas impugnar esto, por favor <1>completa este formulario y lo revisaremos.", + "checkboxLabel": "Entiendo que no recibiré financiación equiparada en esta época.", "goToDisputeForm": "Ir al formulario de disputa", - "close": "Cerca" + "close": "Cerrar" }, "stepsCommon": { "usingTheApp": { "header": "Usando la aplicación", - "text": "Antes de continuar, lea los términos de servicio y haga clic en la casilla de verificación a continuación para aceptarlos.", + "text": "Antes de continuar, lee los términos de servicio y haz clic en la casilla de verificación a continuación para aceptarlos.", "waitingForWalletConfirmation": "Esperando la confirmación de la billetera" }, "signingTheTerms": { @@ -493,45 +493,45 @@ "stepsDecisionWindowOpen": { "welcomeToOctant": { "header": "Bienvenido a Epoch {{epoch}} Asignación", - "text": "Si bloqueaste GLM en la última época, tendrás recompensas disponibles durante esta ventana de asignación, que se extiende hasta {{date}}. De lo contrario, bloquea algún GLM en la vista de Inicio y explora los proyectos de esta época para tener una idea de qué se trata Octant." + "text": "Si bloqueaste tokens GLM en la época anterior, tendrás recompensas disponibles durante esta ventana de asignación, que se extiende hasta {{date}}.

De lo contrario, bloquea algún GLM en la vista de Inicio y explora los proyectos de esta época para tener una idea de qué se trata Octant." }, "earnRewards": { - "header": "Gane recompensas ETH", - "text": "Las recompensas de ETH se obtienen en función de un promedio ponderado, por lo que cuanto más GLM bloquees y cuanto más tiempo lo hagas, más ganarás. Puedes desbloquear en cualquier momento, pero al hacerlo reducirás tus recompensas. Usa la calculadora en la vista de Inicio para estimar las posibles recompensas." + "header": "Gana recompensas ETH", + "text": "Las recompensas de ETH se obtienen en función de un promedio ponderado, por lo que cuanto más tokens GLM bloquees y cuanto más tiempo lo hagas, más ganarás.

Puedes desbloquear en cualquier momento, pero al hacerlo reducirás tus recompensas. Usa la calculadora de recompensas en la vista de Inicio para estimar las posibles recompensas." }, "donateToProjects": { "header": "Donar a proyectos", - "text": "Consulta la programación de Epoch {{epoch}} en la vista de Proyectos. Pulsa el mosaico de un proyecto para leer sus detalles y donar a tus favoritos. Tu donación será igualada por la Fundación Golem. Solo pulsa el corazón para agregar un proyecto al cajón de Asignaciones donde puedes donar." + "text": "Consulta la programación de Epoch {{epoch}} en la vista de Proyectos. Pulsa el mosaico de un proyecto para leer sus detalles y donar a tus favoritos.

Tu donación será igualada por la Fundación Golem. Solo pulsa el corazón para agregar un proyecto al apartado de Asignaciones donde puedes donar." }, "slideIt": { - "header": "Simplemente deslízalo", - "text": "Si tiene recompensas, use el control deslizante en el cajón Asignar para dividirlas fácilmente entre proyectos o entre usted mismo. Para cambiar sus opciones en cualquier momento durante la asignación, simplemente haga clic en Editar, realice algunos cambios y reconfirme en su billetera." + "header": "Solo deslízalo", + "text": "Si tiene recompensas, usa el control deslizante en el apartado de Asignar para dividirlas fácilmente entre proyectos o entre usted mismo.

Para cambiar sus opciones en cualquier momento durante la asignación, simplemente haz clic en Editar, realice algunos cambios y reconfirme en su billetera." } }, "stepsDecisionWindowClosed": { "welcomeToOctant": { "header": "Bienvenido a Octant Epoch {{epoch}}", - "text": "Octant es un experimento de la Fundación Golem en gobernanza descentralizada y financiación de proyectos de bien público. Para comenzar, bloquee algo de GLM en la vista de Inicio y explore los proyectos de esta época para tener una idea de qué se trata Octant." + "text": "Octant es un experimento de la Fundación Golem sobre gobernanza descentralizada y financiación de proyectos de bienes públicos.

Para comenzar, bloquea algunos tokens GLM en el Inicio y explora los proyectos de esta época para tener una idea de qué trata Octant." }, "earnRewards": { - "header": "Gane recompensas ETH", - "text": "Las recompensas de ETH se obtienen en función de un promedio ponderado, por lo que cuanto más GLM bloquees y cuanto más tiempo lo hagas, más ganarás. Puedes desbloquear en cualquier momento, pero al hacerlo reducirás tus recompensas. Usa la calculadora en la vista de Inicio para estimar las posibles recompensas." + "header": "Gana recompensas ETH", + "text": "Las recompensas de ETH se obtienen en función de un promedio ponderado, por lo que cuantos más tokens GLM bloquees y más tiempo lo hagas, más ganarás.

Puedes desbloquear en cualquier momento, pero al hacerlo reducirás tus recompensas. Usa la calculadora en el Inicio para estimar las posibles recompensas." }, "getReady": { - "header": "Prepárese para la asignación", - "text": "Bloquea tu GLM, revisa los proyectos a los que puedes apoyar y prepárate para la próxima ventana de asignación que se abre el {{date}}. Visita <0>Octant.build<\/0>, únete a <1>Discord<\/1> u obtén actualizaciones del proyecto en <2>Twitter<\/2> o <3>Farcaster<\/3>." + "header": "Prepárate para la asignación", + "text": "Bloquea tus tokens GLM, explora los proyectos que puedes apoyar y prepárate para la próxima ventana de asignación que se abre el {{date}}.

Visita <0>Octant.build, únete a <1>Discord u obtén actualizaciones del proyecto en <2>Twitter o <3>Farcaster." } } }, "project": { - "loadingProblem": "Al cargar este proyecto se encontró con un problema.", + "loadingProblem": "Hubo un problema al cargar este proyecto.", "backToTop": "Volver al inicio", "share": "Compartir", "milestones": { "header": "Informes", "milestone": "Hito", "posted": "Al corriente", - "noMilestonesYet": "Aún no hay hitos", + "noMilestonesYet": "Aún no hay objetivos", "buttonExpand": { "readMore": "Leer más", "readLess": "Leer menos" @@ -539,12 +539,12 @@ "viewOnKarmaGap": "Ver en KarmaGap", "viewMoreOnKarmaGap": "Ver más en KarmaGap", "noResults": { - "header": "Aún no hay nada que informar. Vuelva a visitarnos pronto", - "description": "¿Eres administrador de proyectos? Agrega tus informes <0>aquí<\/0>" + "header": "Aún no hay nada que informar. Vuelve pronto para ver las actualizaciones", + "description": "¿Eres administrador de un proyecto? Agrega tus informes <0>aquí" }, "states": { "pending": "Pendiente", - "complete": "Completo", + "complete": "Completado", "all": "Todo" } } @@ -553,36 +553,36 @@ "viewTitle": "Explorar proyectos de Epoch {{epochNumber}}", "projectsTimelineWidget": { "applicationsOpen": "Aplicaciones abiertas", - "projectUpdatesClose": "Actualizaciones del proyecto cerrar", + "projectUpdatesClose": "Cierre de actualizaciones del proyecto", "snapshotVote": "Votación instantánea", "allocationWindow": "Ventana de asignación", "epochStarts": "La época {{epoch}} comienza" }, - "searchInputPlaceholder": "Búsqueda de proyectos y épocas, por ejemplo Tor E1, E2", + "searchInputPlaceholder": "Buscar proyectos y épocas, p. ej. Tor E1, E2", "sortOptions": { "randomized": "Aleatorizado", "alphabeticalAscending": "A -> Z", "alphabeticalDescending": "Z -> A", - "totalsDescending": "Total mayor a menor", - "totalsAscending": "Total menor a mayor", + "totalsDescending": "Total de mayor a menor", + "totalsAscending": "Total de menor a mayor", "donorsDescending": "Donantes de mayor a menor", - "donorsAscending": "De menos a más donantes" + "donorsAscending": "Donantes de menor a mayor" } }, "settings": { "epoch": "Época {{epoch}}", "golemFoundationProject": "Un proyecto de la Fundación Golem", "poweredByCoinGeckoApi": "Desarrollado por la API de CoinGecko", - "chooseDisplayCurrency": "Elija una moneda para visualizar", - "cryptoMainValueDisplay": "Utilice ETH como valor principal de visualización", + "chooseDisplayCurrency": "Elige una moneda para visualizar", + "cryptoMainValueDisplay": "Utiliza ETH como valor principal de visualización", "alwaysShowOnboarding": "Mostrar siempre la incorporación", "showHelpVideos": "Mostrar videos de ayuda", "enablePatronMode": "Habilitar modo mecenas", - "patronModeTooltip": "El modo patrocinador es para los poseedores de tokens que desean apoyar a Octant. Desactiva la asignación a ti mismo o a proyectos. Todas las recompensas van directamente al fondo de contrapartida sin necesidad de que el patrocinador haga nada.", + "patronModeTooltip": "El modo patrocinador es para los poseedores de tokens que desean apoyar a Octant. Desactiva la asignación para ti o a proyectos. Todas las recompensas van directamente al fondo de contrapartida sin necesidad de que el patrocinador haga nada.", "docs": "Documentos" }, "syncStatus": { - "information": "Estamos sincronizando las cosas para preparar la época, por lo que la aplicación no estará disponible por un . Vuelve a visitarnos pronto." + "information": "Estamos sincronizando el sistema para preparar la
siguiente época. La aplicación no estará disponible
por un breve período. Por favor, vuelve pronto." } }, "languageSelector": { From 60ff979d760afeebe2cfc67e284ec52f27c3dc06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Zi=C3=B3=C5=82ek?= Date: Fri, 6 Dec 2024 15:02:16 +0100 Subject: [PATCH 10/12] feat: i18n.language added as a deps so that useMemo is sensitive to language change --- .../AllocationNavigation/AllocationNavigation.tsx | 1 + .../LockGlmBudgetBox/LockGlmBudgetBox.tsx | 4 ++-- .../LockGlmNotification/LockGlmNotification.tsx | 12 ++++++------ .../TransactionLabel/TransactionLabel.tsx | 2 +- .../HomeGridUQScoreAddresses.tsx | 4 ++-- .../src/components/Home/HomeRewards/HomeRewards.tsx | 6 +++--- .../ButtonAddToAllocate/ButtonAddToAllocate.tsx | 4 ++-- .../shared/Layout/LayoutTopBar/LayoutTopBar.tsx | 4 ++-- .../CalendarItem/CalendarItem.tsx | 1 + .../LayoutTopBarCalendar/LayoutTopBarCalendar.tsx | 11 +++++++++-- client/src/components/shared/Rewards/Rewards.tsx | 2 +- client/src/views/HomeView/HomeView.tsx | 5 +++-- 12 files changed, 33 insertions(+), 23 deletions(-) diff --git a/client/src/components/Allocation/AllocationNavigation/AllocationNavigation.tsx b/client/src/components/Allocation/AllocationNavigation/AllocationNavigation.tsx index 18f64c642d..78f1894e81 100644 --- a/client/src/components/Allocation/AllocationNavigation/AllocationNavigation.tsx +++ b/client/src/components/Allocation/AllocationNavigation/AllocationNavigation.tsx @@ -58,6 +58,7 @@ const AllocationNavigation: FC = ({ showTickAnimation, showCircleAnimation, areButtonsDisabled, + i18n.language, ]); useEffect(() => { diff --git a/client/src/components/Home/HomeGridCurrentGlmLock/ModalLockGlm/LockGlmBudgetBox/LockGlmBudgetBox.tsx b/client/src/components/Home/HomeGridCurrentGlmLock/ModalLockGlm/LockGlmBudgetBox/LockGlmBudgetBox.tsx index 9924d1cf86..6d02234591 100644 --- a/client/src/components/Home/HomeGridCurrentGlmLock/ModalLockGlm/LockGlmBudgetBox/LockGlmBudgetBox.tsx +++ b/client/src/components/Home/HomeGridCurrentGlmLock/ModalLockGlm/LockGlmBudgetBox/LockGlmBudgetBox.tsx @@ -25,7 +25,7 @@ const LockGlmBudgetBox: FC = ({ const { data: userRaffleWinnings, isFetching: isFetchingUserRaffleWinnings } = useUserRaffleWinnings(); - const { t } = useTranslation('translation', { + const { t, i18n } = useTranslation('translation', { keyPrefix: 'components.home.homeGridCurrentGlmLock.modalLockGlm.lockGlmBudgetBox', }); @@ -56,7 +56,7 @@ const LockGlmBudgetBox: FC = ({ } return t('walletBalance'); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [shouldRaffleWinningsBeDisplayed, userRaffleWinnings?.winnings.length]); + }, [shouldRaffleWinningsBeDisplayed, userRaffleWinnings?.winnings.length, i18n.language]); return ( = ({ keyPrefix, }); - const label = useMemo(() => { + const labelKey = useMemo(() => { if (type === 'info' && currentMode === 'lock' && !isLockingApproved) { - return t('info.lock.notApproved.label'); + return `${keyPrefix}.info.lock.notApproved.label`; } if (type === 'success' && currentMode === 'lock') { - return t('success.labelLocked'); + return `${keyPrefix}.success.labelLocked`; } if (type === 'success' && currentMode === 'unlock') { - return t('success.labelUnlocked'); + return `${keyPrefix}.success.labelUnlocked`; } - }, [t, currentMode, type, isLockingApproved]); + }, [currentMode, type, isLockingApproved]); const text = useMemo(() => { if (type === 'success') { @@ -55,7 +55,7 @@ const LockGlmNotification: FC = ({
- {label &&
{label}
} + {labelKey &&
{t(labelKey)}
} {text && (
= ({ isFinalized, isMultisig } } return i18n.t('common.pending'); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isFinalized, isMultisig]); + }, [isFinalized, isMultisig, i18n.language]); return
{label}
; }; diff --git a/client/src/components/Home/HomeGridUQScore/HomeGridUQScoreAddresses/HomeGridUQScoreAddresses.tsx b/client/src/components/Home/HomeGridUQScore/HomeGridUQScoreAddresses/HomeGridUQScoreAddresses.tsx index 36f7874897..3ac8da8c0a 100644 --- a/client/src/components/Home/HomeGridUQScore/HomeGridUQScoreAddresses/HomeGridUQScoreAddresses.tsx +++ b/client/src/components/Home/HomeGridUQScore/HomeGridUQScoreAddresses/HomeGridUQScoreAddresses.tsx @@ -18,7 +18,7 @@ const HomeGridUQScoreAddresses: FC = ({ isFetchingScore, isOnTimeOutList, }) => { - const { t } = useTranslation('translation', { + const { t, i18n } = useTranslation('translation', { keyPrefix: 'components.home.homeGridUQScore', }); const ref = useRef(null); @@ -62,7 +62,7 @@ const HomeGridUQScoreAddresses: FC = ({ } return truncateEthAddress(addresses.at(0) || ''); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [showMoreThanOneAddress, addresses, isConnected]); + }, [showMoreThanOneAddress, addresses, isConnected, i18n.language]); useEffect(() => { if (isFetchingScore || !ref?.current || !isConnected) { diff --git a/client/src/components/Home/HomeRewards/HomeRewards.tsx b/client/src/components/Home/HomeRewards/HomeRewards.tsx index c268355bf6..57a018b88a 100644 --- a/client/src/components/Home/HomeRewards/HomeRewards.tsx +++ b/client/src/components/Home/HomeRewards/HomeRewards.tsx @@ -106,7 +106,7 @@ const HomeRewards = (): ReactElement => { } return t('currentRewards'); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isProjectAdminMode, isMobile]); + }, [isProjectAdminMode, isMobile, i18n.language]); const totalRewardsLabel = useMemo(() => { if (isProjectAdminMode) { @@ -117,7 +117,7 @@ const HomeRewards = (): ReactElement => { } return t('totalRewards'); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isProjectAdminMode, isMobile]); + }, [isProjectAdminMode, isMobile, i18n.language]); const rewardsRateLabel = useMemo(() => { if (isProjectAdminMode || isPatronMode) { @@ -128,7 +128,7 @@ const HomeRewards = (): ReactElement => { } return t('rewardsRate'); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isProjectAdminMode, isMobile, isPatronMode]); + }, [isProjectAdminMode, isMobile, isPatronMode, i18n.language]); const tiles = [ { diff --git a/client/src/components/shared/ButtonAddToAllocate/ButtonAddToAllocate.tsx b/client/src/components/shared/ButtonAddToAllocate/ButtonAddToAllocate.tsx index e35de42bbe..a0ef732164 100644 --- a/client/src/components/shared/ButtonAddToAllocate/ButtonAddToAllocate.tsx +++ b/client/src/components/shared/ButtonAddToAllocate/ButtonAddToAllocate.tsx @@ -45,7 +45,7 @@ const ButtonAddToAllocate: FC = ({ } return t('saveToAllocate'); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isAddedToAllocate, isTooltipClicked, isArchivedProject, isAllocatedTo]); + }, [isAddedToAllocate, isTooltipClicked, isArchivedProject, isAllocatedTo, i18n.language]); const ctaButtonText = useMemo(() => { if (isAllocatedTo) { @@ -56,7 +56,7 @@ const ButtonAddToAllocate: FC = ({ } return t('saveProject'); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isAddedToAllocate, isAllocatedTo, isArchivedProject]); + }, [isAddedToAllocate, isAllocatedTo, isArchivedProject, i18n.language]); const handleTooltipVisibilityChange = (isVisible: boolean) => { setIsTooltipVisible(isVisible); diff --git a/client/src/components/shared/Layout/LayoutTopBar/LayoutTopBar.tsx b/client/src/components/shared/Layout/LayoutTopBar/LayoutTopBar.tsx index e39329f12e..2384a5ac93 100644 --- a/client/src/components/shared/Layout/LayoutTopBar/LayoutTopBar.tsx +++ b/client/src/components/shared/Layout/LayoutTopBar/LayoutTopBar.tsx @@ -31,7 +31,7 @@ import LayoutTopBarProps from './types'; const LayoutTopBar: FC = ({ className }) => { const dataTestRoot = 'LayoutTopBar'; - const { t } = useTranslation('translation', { keyPrefix: 'layout.topBar' }); + const { t, i18n } = useTranslation('translation', { keyPrefix: 'layout.topBar' }); const { isDesktop, isMobile } = useMediaQuery(); const { isConnected, address } = useAccount(); const { pathname } = useLocation(); @@ -73,7 +73,7 @@ const LayoutTopBar: FC = ({ className }) => { return truncateEthAddress(address!, isMobile); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [address, isConnected, isMobile, isProjectAdminMode, isPatronMode]); + }, [address, isConnected, isMobile, isProjectAdminMode, isPatronMode, i18n.language]); const onLogoClick = () => { if (pathname === ROOT_ROUTES.home.absolute) { diff --git a/client/src/components/shared/Layout/LayoutTopBarCalendar/CalendarItem/CalendarItem.tsx b/client/src/components/shared/Layout/LayoutTopBarCalendar/CalendarItem/CalendarItem.tsx index fe4c0e042b..040039ff16 100644 --- a/client/src/components/shared/Layout/LayoutTopBarCalendar/CalendarItem/CalendarItem.tsx +++ b/client/src/components/shared/Layout/LayoutTopBarCalendar/CalendarItem/CalendarItem.tsx @@ -58,6 +58,7 @@ const CalendarItem: FC = ({ isHovered, durationToChangeAWInMinutes, shouldUseThirdPersonSingularVerb, + i18n.language, ]); return ( diff --git a/client/src/components/shared/Layout/LayoutTopBarCalendar/LayoutTopBarCalendar.tsx b/client/src/components/shared/Layout/LayoutTopBarCalendar/LayoutTopBarCalendar.tsx index 0634fae504..f07d854ff6 100644 --- a/client/src/components/shared/Layout/LayoutTopBarCalendar/LayoutTopBarCalendar.tsx +++ b/client/src/components/shared/Layout/LayoutTopBarCalendar/LayoutTopBarCalendar.tsx @@ -17,7 +17,7 @@ import { calendar } from 'svg/misc'; import styles from './LayoutTopBarCalendar.module.scss'; const LayoutTopBarCalendar = (): ReactElement => { - const { t } = useTranslation('translation', { keyPrefix: 'layout.topBar' }); + const { t, i18n } = useTranslation('translation', { keyPrefix: 'layout.topBar' }); const { isMobile } = useMediaQuery(); const { data: isDecisionWindowOpen } = useIsDecisionWindowOpen(); const { data: currentEpoch } = useCurrentEpoch(); @@ -67,7 +67,14 @@ const LayoutTopBarCalendar = (): ReactElement => { } return t('epochAllocationOpensIn', { duration, epoch }); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isDecisionWindowOpen, currentEpoch, isMobile, durationToChangeAWInMinutes, showAWAlert]); + }, [ + isDecisionWindowOpen, + currentEpoch, + isMobile, + durationToChangeAWInMinutes, + showAWAlert, + i18n.language, + ]); useEffect(() => { if ( diff --git a/client/src/components/shared/Rewards/Rewards.tsx b/client/src/components/shared/Rewards/Rewards.tsx index 3af628dbac..7d20ada2ad 100644 --- a/client/src/components/shared/Rewards/Rewards.tsx +++ b/client/src/components/shared/Rewards/Rewards.tsx @@ -100,7 +100,7 @@ const Rewards: FC = ({ } return i18n.t('common.totalDonated'); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isArchivedProject]); + }, [isArchivedProject, i18n.language]); const showMiddleSections = showMoreInfo && (isLargeDesktop || isDesktop); diff --git a/client/src/views/HomeView/HomeView.tsx b/client/src/views/HomeView/HomeView.tsx index 852186cc29..0be2ecc6ba 100644 --- a/client/src/views/HomeView/HomeView.tsx +++ b/client/src/views/HomeView/HomeView.tsx @@ -11,7 +11,7 @@ import useIsDecisionWindowOpen from 'hooks/queries/useIsDecisionWindowOpen'; import styles from './HomeView.module.scss'; const HomeView = (): ReactElement => { - const { t } = useTranslation('translation', { keyPrefix: 'views.home' }); + const { t, i18n } = useTranslation('translation', { keyPrefix: 'views.home' }); const { isMobile } = useMediaQuery(); const { data: currentEpoch } = useCurrentEpoch(); const { data: isDecisionWindowOpen } = useIsDecisionWindowOpen(); @@ -24,7 +24,8 @@ const HomeView = (): ReactElement => { return t('title.isDecisionWindowOpenTrue.desktop', { epoch: currentEpoch! - 1 }); } return t('title.isDecisionWindowOpenFalse', { epoch: currentEpoch }); - }, [currentEpoch, t, isMobile, isDecisionWindowOpen]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [currentEpoch, t, isMobile, isDecisionWindowOpen, i18n.language]); return (
From 3b5391b0e76fa85ad6da97b16f9d09e70f39f511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Zi=C3=B3=C5=82ek?= Date: Fri, 6 Dec 2024 15:07:43 +0100 Subject: [PATCH 11/12] style: move i18n into consts --- .../LanguageSelector/LanguageSelector.tsx | 13 ++---------- client/src/i18n.ts | 9 ++++---- client/src/i18n/languages.ts | 21 +++++++++++++++++++ 3 files changed, 28 insertions(+), 15 deletions(-) create mode 100644 client/src/i18n/languages.ts diff --git a/client/src/components/shared/LanguageSelector/LanguageSelector.tsx b/client/src/components/shared/LanguageSelector/LanguageSelector.tsx index 5500f926af..4104fac870 100644 --- a/client/src/components/shared/LanguageSelector/LanguageSelector.tsx +++ b/client/src/components/shared/LanguageSelector/LanguageSelector.tsx @@ -2,8 +2,8 @@ import React, { ReactElement } from 'react'; import { useTranslation } from 'react-i18next'; import InputSelect from 'components/ui/InputSelect'; -import { Option } from 'components/ui/InputSelect/types'; import Svg from 'components/ui/Svg'; +import { getLanguageOptions } from 'i18n/languages'; import { earth } from 'svg/misc'; import styles from './LanguageSelector.module.scss'; @@ -11,16 +11,7 @@ import styles from './LanguageSelector.module.scss'; const LanguageSelector = (): ReactElement => { const { t, i18n } = useTranslation('translation'); - const languageOptions: Option[] = [ - { - label: t('languageSelector.english'), - value: 'en-EN', - }, - { - label: t('languageSelector.spanish'), - value: 'es-Es', - }, - ]; + const languageOptions = getLanguageOptions(t); return ( [ + { + label: t('languageSelector.english'), + value: languageKey.enEn, + }, + { + label: t('languageSelector.spanish'), + value: languageKey.esEs, + }, +]; From d6b4885dd1ba4ae64cc4ed8f21039d5dfc56d54f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20Zi=C3=B3=C5=82ek?= Date: Fri, 6 Dec 2024 15:15:49 +0100 Subject: [PATCH 12/12] feat: save language into localStorage --- .../components/shared/LanguageSelector/LanguageSelector.tsx | 6 +++++- client/src/constants/localStorageKeys.ts | 2 ++ client/src/i18n.ts | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/client/src/components/shared/LanguageSelector/LanguageSelector.tsx b/client/src/components/shared/LanguageSelector/LanguageSelector.tsx index 4104fac870..28466ee8b0 100644 --- a/client/src/components/shared/LanguageSelector/LanguageSelector.tsx +++ b/client/src/components/shared/LanguageSelector/LanguageSelector.tsx @@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next'; import InputSelect from 'components/ui/InputSelect'; import Svg from 'components/ui/Svg'; +import { LANGUAGE_UI } from 'constants/localStorageKeys'; import { getLanguageOptions } from 'i18n/languages'; import { earth } from 'svg/misc'; @@ -17,7 +18,10 @@ const LanguageSelector = (): ReactElement => { } - onChange={option => i18n.changeLanguage(option!.value)} + onChange={({ value }) => { + localStorage.setItem(LANGUAGE_UI, value); + i18n.changeLanguage(value); + }} options={languageOptions} selectedOption={languageOptions.find(({ value }) => value === i18n.language)} variant="topselect" diff --git a/client/src/constants/localStorageKeys.ts b/client/src/constants/localStorageKeys.ts index 5b5f37c79f..67c42f40ce 100644 --- a/client/src/constants/localStorageKeys.ts +++ b/client/src/constants/localStorageKeys.ts @@ -41,6 +41,8 @@ export const IS_CRYPTO_MAIN_VALUE_DISPLAY = getLocalStorageKey( export const SHOW_HELP_VIDEOS = getLocalStorageKey(settingsPrefix, 'showHelpVideos'); +export const LANGUAGE_UI = getLocalStorageKey(settingsPrefix, 'languageUI'); + // Delegation const delegationPrefix = 'delegation_5'; diff --git a/client/src/i18n.ts b/client/src/i18n.ts index 2b49d83bfd..bec9a42d0d 100644 --- a/client/src/i18n.ts +++ b/client/src/i18n.ts @@ -1,6 +1,7 @@ import i18n from 'i18next'; import { initReactI18next } from 'react-i18next'; +import { LANGUAGE_UI } from 'constants/localStorageKeys'; import { defaultLang, languageKey } from 'i18n/languages'; import translationEN from 'locales/en/translation.json'; import translationES from 'locales/es/translation.json'; @@ -16,7 +17,7 @@ i18n.use(initReactI18next).init({ interpolation: { escapeValue: false, }, - lng: defaultLang, + lng: localStorage.getItem(LANGUAGE_UI) || defaultLang, resources: { [languageKey.enEn]: { translation: translationEN,