@hotosm/hanko-auth 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hanko-auth.esm.js +3191 -3323
- package/dist/hanko-auth.iife.js +62 -59
- package/dist/hanko-auth.umd.js +62 -59
- package/package.json +1 -1
- package/src/hanko-auth.styles.ts +9 -5
- package/src/hanko-auth.ts +91 -11
- package/src/hanko-i18n-en.ts +20 -0
- package/src/hanko-i18n-es.ts +4 -4
- package/src/hanko-i18n-fr.ts +4 -4
- package/src/hanko-i18n-pt.ts +7 -10
- package/src/hanko-translations.ts +15 -0
- package/src/translations.ts +10 -0
package/package.json
CHANGED
package/src/hanko-auth.styles.ts
CHANGED
|
@@ -6,10 +6,14 @@ export const styles = css`
|
|
|
6
6
|
font-family: var(--font-family, var(--hot-font-sans));
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
hanko-auth::part(headline1) {
|
|
10
|
+
text-align: center;
|
|
11
|
+
}
|
|
12
|
+
|
|
9
13
|
.container {
|
|
10
14
|
max-width: 400px;
|
|
11
15
|
margin: 0 auto;
|
|
12
|
-
padding: var(--hot-spacing-large);
|
|
16
|
+
padding: var(--hot-spacing-x-small) var(--hot-spacing-large);
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
.loading {
|
|
@@ -32,13 +36,12 @@ export const styles = css`
|
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
.spinner {
|
|
35
|
-
width:
|
|
36
|
-
height:
|
|
37
|
-
border: 4px solid var(--hot-color-
|
|
39
|
+
width: 25px;
|
|
40
|
+
height: 25px;
|
|
41
|
+
border: 4px solid var(--hot-color-red-50);
|
|
38
42
|
border-top: 4px solid var(--hot-color-red-600);
|
|
39
43
|
border-radius: 50%;
|
|
40
44
|
animation: spin 1s linear infinite;
|
|
41
|
-
margin: 0 auto;
|
|
42
45
|
}
|
|
43
46
|
/* Container that mimics the avatar/dropdown-trigger dimensions */
|
|
44
47
|
.loading-placeholder {
|
|
@@ -521,5 +524,6 @@ export const styles = css`
|
|
|
521
524
|
/* Style Hanko's internal link button (e.g. "Create account") */
|
|
522
525
|
hanko-auth::part(link) {
|
|
523
526
|
font-weight: bold;
|
|
527
|
+
text-decoration: underline;
|
|
524
528
|
}
|
|
525
529
|
`;
|
package/src/hanko-auth.ts
CHANGED
|
@@ -6,10 +6,7 @@ import { keyed } from "lit/directives/keyed.js";
|
|
|
6
6
|
import { register } from "@teamhanko/hanko-elements";
|
|
7
7
|
import { styles } from "./hanko-auth.styles";
|
|
8
8
|
// hanko ui translations
|
|
9
|
-
import {
|
|
10
|
-
import { es } from "./hanko-i18n-es";
|
|
11
|
-
import { fr } from "./hanko-i18n-fr";
|
|
12
|
-
import { pt } from "./hanko-i18n-pt";
|
|
9
|
+
import { getTranslations } from "./hanko-translations";
|
|
13
10
|
// custom component translations
|
|
14
11
|
import { translations } from "./translations";
|
|
15
12
|
|
|
@@ -36,7 +33,7 @@ async function ensureHankoRegistered(hankoUrl: string): Promise<void> {
|
|
|
36
33
|
await register(hankoUrl, {
|
|
37
34
|
enablePasskeys: false,
|
|
38
35
|
hidePasskeyButtonOnLogin: true,
|
|
39
|
-
translations:
|
|
36
|
+
translations: getTranslations(),
|
|
40
37
|
fallbackLanguage: "en",
|
|
41
38
|
});
|
|
42
39
|
hankoRegistered = true;
|
|
@@ -198,6 +195,28 @@ export class HankoAuth extends LitElement {
|
|
|
198
195
|
private _lastSessionId: string | null = null;
|
|
199
196
|
private _hanko: any = null;
|
|
200
197
|
private _isPrimary = false; // Is this the primary instance?
|
|
198
|
+
private _hankoObserver: MutationObserver | null = null;
|
|
199
|
+
|
|
200
|
+
// Hanko signup headline text across all supported languages (used for subtitle injection)
|
|
201
|
+
private _signUpHeadlines = new Set([
|
|
202
|
+
"Create an account", // en (our override)
|
|
203
|
+
"Crear cuenta", // es
|
|
204
|
+
"Créer un compte", // fr
|
|
205
|
+
"Criar conta", // pt
|
|
206
|
+
]);
|
|
207
|
+
|
|
208
|
+
// Hanko initial login (email entry) headline text across all supported languages
|
|
209
|
+
// Covers both loginEmail and loginEmailNoSignup variants
|
|
210
|
+
private _loginHeadlines = new Set([
|
|
211
|
+
"Sign in or create account", // en loginEmail
|
|
212
|
+
"Sign in", // en loginEmailNoSignup
|
|
213
|
+
"Iniciar sesión o crear cuenta", // es loginEmail
|
|
214
|
+
"Iniciar sesión", // es loginEmailNoSignup
|
|
215
|
+
"Se connecter ou s'inscrire", // fr loginEmail
|
|
216
|
+
"Se connecter", // fr loginEmailNoSignup
|
|
217
|
+
"Entrar ou criar conta", // pt loginEmail
|
|
218
|
+
"Entrar", // pt loginEmailNoSignup
|
|
219
|
+
]);
|
|
201
220
|
|
|
202
221
|
constructor() {
|
|
203
222
|
super();
|
|
@@ -929,6 +948,7 @@ export class HankoAuth extends LitElement {
|
|
|
929
948
|
if (hankoAuth) {
|
|
930
949
|
this._currentHankoAuthElement = hankoAuth;
|
|
931
950
|
this.log("Attaching event listeners to hanko-auth element");
|
|
951
|
+
this._setupSignUpSubtitleObserver(hankoAuth);
|
|
932
952
|
|
|
933
953
|
hankoAuth.addEventListener("onSessionCreated", (e: any) => {
|
|
934
954
|
this.log(`Hanko event: onSessionCreated`, e.detail);
|
|
@@ -950,6 +970,67 @@ export class HankoAuth extends LitElement {
|
|
|
950
970
|
});
|
|
951
971
|
}
|
|
952
972
|
|
|
973
|
+
private _setupSignUpSubtitleObserver(hankoAuth: Element) {
|
|
974
|
+
const injectSubtitle = () => {
|
|
975
|
+
const hankoShadow = (hankoAuth as HTMLElement & { shadowRoot: ShadowRoot | null }).shadowRoot;
|
|
976
|
+
if (!hankoShadow) return;
|
|
977
|
+
|
|
978
|
+
const h1 = hankoShadow.querySelector<HTMLElement>("h1[part='headline1']");
|
|
979
|
+
const headlineText = h1?.textContent?.trim() ?? "";
|
|
980
|
+
|
|
981
|
+
// Remove any existing subtitle first
|
|
982
|
+
const existing = hankoShadow.querySelector(".hot-subtitle");
|
|
983
|
+
|
|
984
|
+
const isSignUp = this._signUpHeadlines.has(headlineText);
|
|
985
|
+
const isLogin = this._loginHeadlines.has(headlineText);
|
|
986
|
+
|
|
987
|
+
// Only show subtitle on the two initial screens
|
|
988
|
+
if (!isSignUp && !isLogin) {
|
|
989
|
+
if (existing) {
|
|
990
|
+
this._hankoObserver?.disconnect();
|
|
991
|
+
existing.remove();
|
|
992
|
+
this._hankoObserver?.observe(hankoShadow, { childList: true, subtree: true });
|
|
993
|
+
}
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
const subtitleText = isSignUp
|
|
998
|
+
? this.t("signUpSubtitle")
|
|
999
|
+
: this.t("loginSubtitle");
|
|
1000
|
+
|
|
1001
|
+
// Skip if subtitle already has correct text
|
|
1002
|
+
if (existing && existing.textContent === subtitleText) return;
|
|
1003
|
+
if (!h1) return;
|
|
1004
|
+
|
|
1005
|
+
// Disconnect before modifying DOM to avoid re-triggering the observer
|
|
1006
|
+
this._hankoObserver?.disconnect();
|
|
1007
|
+
|
|
1008
|
+
if (existing) existing.remove();
|
|
1009
|
+
|
|
1010
|
+
const subtitle = document.createElement("p");
|
|
1011
|
+
subtitle.className = "hot-subtitle";
|
|
1012
|
+
subtitle.textContent = subtitleText;
|
|
1013
|
+
subtitle.style.cssText =
|
|
1014
|
+
"margin: -4px 0 16px; text-align: center; font-size: var(--hot-font-size-base, 16px); color: var(--hot-color-gray-600, #6b7280); font-weight: normal;";
|
|
1015
|
+
|
|
1016
|
+
h1.insertAdjacentElement("afterend", subtitle);
|
|
1017
|
+
|
|
1018
|
+
// Re-observe after injection
|
|
1019
|
+
this._hankoObserver?.observe(hankoShadow, { childList: true, subtree: true });
|
|
1020
|
+
};
|
|
1021
|
+
|
|
1022
|
+
if (this._hankoObserver) {
|
|
1023
|
+
this._hankoObserver.disconnect();
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
const hankoShadow = (hankoAuth as HTMLElement & { shadowRoot: ShadowRoot | null }).shadowRoot;
|
|
1027
|
+
if (hankoShadow) {
|
|
1028
|
+
this._hankoObserver = new MutationObserver(() => injectSubtitle());
|
|
1029
|
+
this._hankoObserver.observe(hankoShadow, { childList: true, subtree: true });
|
|
1030
|
+
injectSubtitle();
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
|
|
953
1034
|
private async handleHankoSuccess(event: any) {
|
|
954
1035
|
this.log("Hanko auth success:", event.detail);
|
|
955
1036
|
|
|
@@ -1444,7 +1525,6 @@ window.location.href = redirectUrl;
|
|
|
1444
1525
|
<div class="osm-section">
|
|
1445
1526
|
<div class="osm-connected">
|
|
1446
1527
|
<div class="osm-badge">
|
|
1447
|
-
<span class="osm-badge-icon">🗺️</span>
|
|
1448
1528
|
<div>
|
|
1449
1529
|
<div>${this.t("connectedToOpenStreetMap")}</div>
|
|
1450
1530
|
${this.osmData?.osm_username
|
|
@@ -1633,7 +1713,7 @@ window.location.href = redirectUrl;
|
|
|
1633
1713
|
--color: var(--hot-color-gray-900);
|
|
1634
1714
|
--color-shade-1: var(--hot-color-gray-700);
|
|
1635
1715
|
--color-shade-2: var(--hot-color-gray-100);
|
|
1636
|
-
--brand-color: var(--hot-color-gray-
|
|
1716
|
+
--brand-color: var(--hot-color-gray-1000);
|
|
1637
1717
|
--brand-color-shade-1: var(--hot-color-gray-900);
|
|
1638
1718
|
--brand-contrast-color: white;
|
|
1639
1719
|
--background-color: white;
|
|
@@ -1645,7 +1725,7 @@ window.location.href = redirectUrl;
|
|
|
1645
1725
|
--item-height: 2.75rem;
|
|
1646
1726
|
--item-margin: var(--hot-spacing-small) 0;
|
|
1647
1727
|
--container-padding: 0;
|
|
1648
|
-
--headline1-font-size: var(--hot-font-size-
|
|
1728
|
+
--headline1-font-size: var(--hot-font-size-xl);
|
|
1649
1729
|
--headline1-font-weight: var(--hot-font-weight-semibold);
|
|
1650
1730
|
--headline2-font-size: var(--hot-font-size-medium);
|
|
1651
1731
|
--headline2-font-weight: var(--hot-font-weight-semibold);
|
|
@@ -1653,7 +1733,7 @@ window.location.href = redirectUrl;
|
|
|
1653
1733
|
>
|
|
1654
1734
|
${keyed(
|
|
1655
1735
|
this.lang,
|
|
1656
|
-
html`<hanko-auth lang="${this.lang}"></hanko-auth>`,
|
|
1736
|
+
html`<hanko-auth lang="${this.lang}" exportparts="link"></hanko-auth>`,
|
|
1657
1737
|
)}
|
|
1658
1738
|
</div>
|
|
1659
1739
|
`;
|
|
@@ -1698,5 +1778,5 @@ declare global {
|
|
|
1698
1778
|
}
|
|
1699
1779
|
}
|
|
1700
1780
|
|
|
1701
|
-
// Re-export
|
|
1702
|
-
export {
|
|
1781
|
+
// Re-export for use by consuming apps
|
|
1782
|
+
export { getTranslations } from "./hanko-translations";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* English (en) overrides for Hanko Elements
|
|
3
|
+
* Only include keys that differ from the default Hanko English translations.
|
|
4
|
+
* These are merged on top of enBase in hanko-auth.ts.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export const enOverrides = {
|
|
8
|
+
headlines: {
|
|
9
|
+
signUp: "Create an account",
|
|
10
|
+
},
|
|
11
|
+
labels: {
|
|
12
|
+
signUp: "Create an account",
|
|
13
|
+
alreadyHaveAnAccount: "Already have a HOT account?",
|
|
14
|
+
signIn: "Sign in here",
|
|
15
|
+
},
|
|
16
|
+
texts: {
|
|
17
|
+
enterPasscode:
|
|
18
|
+
"Please enter below the passcode we’ve sent to your email address:",
|
|
19
|
+
},
|
|
20
|
+
};
|
package/src/hanko-i18n-es.ts
CHANGED
|
@@ -48,12 +48,13 @@ export const es = {
|
|
|
48
48
|
deleteSecurityKey: "Eliminar clave de seguridad",
|
|
49
49
|
securityKeys: "Claves de seguridad",
|
|
50
50
|
authenticatorApp: "Aplicación de autenticación",
|
|
51
|
-
authenticatorAppAlreadySetUp:
|
|
51
|
+
authenticatorAppAlreadySetUp:
|
|
52
|
+
"La aplicación de autenticación está configurada",
|
|
52
53
|
authenticatorAppNotSetUp: "Configurar aplicación de autenticación",
|
|
53
54
|
trustDevice: "¿Confiar en este navegador?",
|
|
54
55
|
},
|
|
55
56
|
texts: {
|
|
56
|
-
enterPasscode:
|
|
57
|
+
enterPasscode: "Ingrese el código que se envió a su correo electrónico:",
|
|
57
58
|
enterPasscodeNoEmail:
|
|
58
59
|
"Ingrese el código que se envió a su dirección de correo principal.",
|
|
59
60
|
setupPasskey:
|
|
@@ -172,8 +173,7 @@ export const es = {
|
|
|
172
173
|
"El código se ha ingresado incorrectamente demasiadas veces. Por favor, solicite un nuevo código.",
|
|
173
174
|
tooManyRequests:
|
|
174
175
|
"Se han realizado demasiadas solicitudes. Por favor, espere para repetir la operación solicitada.",
|
|
175
|
-
unauthorized:
|
|
176
|
-
"Su sesión ha expirado. Por favor, inicie sesión nuevamente.",
|
|
176
|
+
unauthorized: "Su sesión ha expirado. Por favor, inicie sesión nuevamente.",
|
|
177
177
|
invalidWebauthnCredential: "Esta llave de acceso ya no se puede usar.",
|
|
178
178
|
passcodeExpired: "El código ha expirado. Por favor, solicite uno nuevo.",
|
|
179
179
|
userVerification:
|
package/src/hanko-i18n-fr.ts
CHANGED
|
@@ -48,12 +48,13 @@ export const fr = {
|
|
|
48
48
|
deleteSecurityKey: "Supprimer la clé de sécurité",
|
|
49
49
|
securityKeys: "Clés de sécurité",
|
|
50
50
|
authenticatorApp: "Application d'authentification",
|
|
51
|
-
authenticatorAppAlreadySetUp:
|
|
51
|
+
authenticatorAppAlreadySetUp:
|
|
52
|
+
"L'application d'authentification est configurée",
|
|
52
53
|
authenticatorAppNotSetUp: "Configurer l'application d'authentification",
|
|
53
54
|
trustDevice: "Faire confiance à ce navigateur ?",
|
|
54
55
|
},
|
|
55
56
|
texts: {
|
|
56
|
-
enterPasscode:
|
|
57
|
+
enterPasscode: "Entrez le code envoyé à votre adresse e-mail:",
|
|
57
58
|
enterPasscodeNoEmail:
|
|
58
59
|
"Entrez le code envoyé à votre adresse e-mail principale.",
|
|
59
60
|
setupPasskey:
|
|
@@ -172,8 +173,7 @@ export const fr = {
|
|
|
172
173
|
"Le code a été saisi incorrectement trop de fois. Veuillez demander un nouveau code.",
|
|
173
174
|
tooManyRequests:
|
|
174
175
|
"Trop de demandes ont été effectuées. Veuillez attendre avant de répéter l'opération demandée.",
|
|
175
|
-
unauthorized:
|
|
176
|
-
"Votre session a expiré. Veuillez vous reconnecter.",
|
|
176
|
+
unauthorized: "Votre session a expiré. Veuillez vous reconnecter.",
|
|
177
177
|
invalidWebauthnCredential: "Cette clé d'accès ne peut plus être utilisée.",
|
|
178
178
|
passcodeExpired: "Le code a expiré. Veuillez en demander un nouveau.",
|
|
179
179
|
userVerification:
|
package/src/hanko-i18n-pt.ts
CHANGED
|
@@ -48,12 +48,13 @@ export const pt = {
|
|
|
48
48
|
deleteSecurityKey: "Excluir chave de segurança",
|
|
49
49
|
securityKeys: "Chaves de segurança",
|
|
50
50
|
authenticatorApp: "Aplicativo de autenticação",
|
|
51
|
-
authenticatorAppAlreadySetUp:
|
|
51
|
+
authenticatorAppAlreadySetUp:
|
|
52
|
+
"O aplicativo de autenticação está configurado",
|
|
52
53
|
authenticatorAppNotSetUp: "Configurar aplicativo de autenticação",
|
|
53
54
|
trustDevice: "Confiar neste navegador?",
|
|
54
55
|
},
|
|
55
56
|
texts: {
|
|
56
|
-
enterPasscode:
|
|
57
|
+
enterPasscode: "Digite o código enviado para o seu endereço de e-mail:",
|
|
57
58
|
enterPasscodeNoEmail:
|
|
58
59
|
"Digite o código enviado para seu endereço de e-mail principal.",
|
|
59
60
|
setupPasskey:
|
|
@@ -65,8 +66,7 @@ export const pt = {
|
|
|
65
66
|
otpScanQRCode:
|
|
66
67
|
"Digitalize o código QR usando seu aplicativo de autenticação (como Google Authenticator ou qualquer outro aplicativo TOTP). Alternativamente, você pode inserir manualmente a chave secreta OTP no aplicativo.",
|
|
67
68
|
otpSecretKey: "Chave secreta OTP",
|
|
68
|
-
passwordFormatHint:
|
|
69
|
-
"Deve ter entre {minLength} e {maxLength} caracteres.",
|
|
69
|
+
passwordFormatHint: "Deve ter entre {minLength} e {maxLength} caracteres.",
|
|
70
70
|
securityKeySetUp:
|
|
71
71
|
"Use uma chave de segurança dedicada via USB, Bluetooth ou NFC, ou seu telefone celular. Conecte ou ative sua chave de segurança, depois clique no botão abaixo e siga as instruções para concluir o registro.",
|
|
72
72
|
setPrimaryEmail:
|
|
@@ -172,8 +172,7 @@ export const pt = {
|
|
|
172
172
|
"O código foi inserido incorretamente muitas vezes. Por favor, solicite um novo código.",
|
|
173
173
|
tooManyRequests:
|
|
174
174
|
"Muitas solicitações foram feitas. Por favor, aguarde antes de repetir a operação solicitada.",
|
|
175
|
-
unauthorized:
|
|
176
|
-
"Sua sessão expirou. Por favor, faça login novamente.",
|
|
175
|
+
unauthorized: "Sua sessão expirou. Por favor, faça login novamente.",
|
|
177
176
|
invalidWebauthnCredential: "Esta chave de acesso não pode mais ser usada.",
|
|
178
177
|
passcodeExpired: "O código expirou. Por favor, solicite um novo.",
|
|
179
178
|
userVerification:
|
|
@@ -194,8 +193,7 @@ export const pt = {
|
|
|
194
193
|
flowErrors: {
|
|
195
194
|
technical_error:
|
|
196
195
|
"Ocorreu um erro técnico. Por favor, tente novamente mais tarde.",
|
|
197
|
-
flow_expired_error:
|
|
198
|
-
"A sessão expirou, clique no botão para reiniciar.",
|
|
196
|
+
flow_expired_error: "A sessão expirou, clique no botão para reiniciar.",
|
|
199
197
|
value_invalid_error: "O valor inserido não é válido.",
|
|
200
198
|
passcode_invalid: "O código fornecido não está correto.",
|
|
201
199
|
passkey_invalid: "Esta chave de acesso não pode mais ser usada.",
|
|
@@ -213,8 +211,7 @@ export const pt = {
|
|
|
213
211
|
operation_not_permitted_error: "A operação não é permitida.",
|
|
214
212
|
flow_discontinuity_error:
|
|
215
213
|
"O processo não pode continuar devido à configuração do usuário ou do provedor.",
|
|
216
|
-
form_data_invalid_error:
|
|
217
|
-
"Os dados do formulário enviados contêm erros.",
|
|
214
|
+
form_data_invalid_error: "Os dados do formulário enviados contêm erros.",
|
|
218
215
|
unauthorized: "Sua sessão expirou. Por favor, faça login novamente.",
|
|
219
216
|
value_missing_error: "O valor está faltando.",
|
|
220
217
|
value_too_long_error: "O valor é muito longo.",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/* overrides for Hanko's UI */
|
|
2
|
+
|
|
3
|
+
import { en } from "@teamhanko/hanko-elements/i18n/en";
|
|
4
|
+
import { enOverrides } from "./hanko-i18n-en";
|
|
5
|
+
import { es } from "./hanko-i18n-es";
|
|
6
|
+
import { fr } from "./hanko-i18n-fr";
|
|
7
|
+
import { pt } from "./hanko-i18n-pt";
|
|
8
|
+
|
|
9
|
+
Object.assign(en.headlines, enOverrides.headlines);
|
|
10
|
+
Object.assign(en.labels, enOverrides.labels);
|
|
11
|
+
Object.assign(en.texts, enOverrides.texts);
|
|
12
|
+
|
|
13
|
+
export function getTranslations() {
|
|
14
|
+
return { en, es, fr, pt };
|
|
15
|
+
}
|
package/src/translations.ts
CHANGED
|
@@ -17,6 +17,8 @@ export interface Translations {
|
|
|
17
17
|
openAccountMenu: string;
|
|
18
18
|
connectedToOsmAs: string;
|
|
19
19
|
osmConnectionRequired: string;
|
|
20
|
+
signUpSubtitle: string;
|
|
21
|
+
loginSubtitle: string;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
export const translations: Record<string, Translations> = {
|
|
@@ -35,6 +37,8 @@ export const translations: Record<string, Translations> = {
|
|
|
35
37
|
openAccountMenu: "Open account menu",
|
|
36
38
|
connectedToOsmAs: "Connected to OSM as",
|
|
37
39
|
osmConnectionRequired: "OSM connection required",
|
|
40
|
+
signUpSubtitle: "Access all HOT tools and services",
|
|
41
|
+
loginSubtitle: "With your HOT account",
|
|
38
42
|
},
|
|
39
43
|
es: {
|
|
40
44
|
logIn: "Iniciar sesión",
|
|
@@ -51,6 +55,8 @@ export const translations: Record<string, Translations> = {
|
|
|
51
55
|
openAccountMenu: "Abrir menú de cuenta",
|
|
52
56
|
connectedToOsmAs: "Conectado a OSM como",
|
|
53
57
|
osmConnectionRequired: "Se requiere conexión OSM",
|
|
58
|
+
signUpSubtitle: "Accede a todas las herramientas y servicios de HOT",
|
|
59
|
+
loginSubtitle: "Con tu cuenta HOT",
|
|
54
60
|
},
|
|
55
61
|
fr: {
|
|
56
62
|
logIn: "Se connecter",
|
|
@@ -67,6 +73,8 @@ export const translations: Record<string, Translations> = {
|
|
|
67
73
|
openAccountMenu: "Ouvrir le menu du compte",
|
|
68
74
|
connectedToOsmAs: "Connecté à OSM en tant que",
|
|
69
75
|
osmConnectionRequired: "Connexion OSM requise",
|
|
76
|
+
signUpSubtitle: "Accédez à tous les outils et services HOT",
|
|
77
|
+
loginSubtitle: "Avec votre compte HOT",
|
|
70
78
|
},
|
|
71
79
|
pt: {
|
|
72
80
|
logIn: "Entrar",
|
|
@@ -83,5 +91,7 @@ export const translations: Record<string, Translations> = {
|
|
|
83
91
|
openAccountMenu: "Abrir menu da conta",
|
|
84
92
|
connectedToOsmAs: "Conectado ao OSM como",
|
|
85
93
|
osmConnectionRequired: "Conexão OSM necessária",
|
|
94
|
+
signUpSubtitle: "Acesse todas as ferramentas e serviços HOT",
|
|
95
|
+
loginSubtitle: "Com a sua conta HOT",
|
|
86
96
|
},
|
|
87
97
|
};
|