@hotosm/hanko-auth 0.5.0 → 0.5.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotosm/hanko-auth",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Web component for HOTOSM SSO authentication with Hanko and OSM integration",
5
5
  "type": "module",
6
6
  "main": "dist/hanko-auth.umd.js",
@@ -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: clamp(40px, 10%, 60px);
36
- height: clamp(40px, 10%, 60px);
37
- border: 4px solid var(--hot-color-gray-50);
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 { en } from "@teamhanko/hanko-elements/i18n/en";
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: { en, es, fr, pt },
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();
@@ -902,33 +921,37 @@ export class HankoAuth extends LitElement {
902
921
 
903
922
  updated(changedProperties: Map<string, any>) {
904
923
  super.updated(changedProperties);
905
- // Re-attach event listeners when user becomes null (after logout)
906
- // because a new <hanko-auth> element is created
907
924
  if (
908
- changedProperties.has("user") &&
909
- this.user === null &&
910
- this.showProfile
925
+ (changedProperties.has("user") && this.user === null && this.showProfile) ||
926
+ changedProperties.has("lang")
911
927
  ) {
912
- this.log("User logged out, re-attaching event listeners...");
913
928
  this._currentHankoAuthElement = null;
914
929
  this.setupEventListeners();
915
930
  }
916
931
  }
917
932
 
918
933
  private setupEventListeners() {
919
- // Use updateComplete to ensure DOM is ready
920
934
  this.updateComplete.then(() => {
921
935
  const hankoAuth = this.shadowRoot?.querySelector("hanko-auth");
922
936
 
923
- // Skip if already attached to the same element
924
937
  if (hankoAuth && hankoAuth === this._currentHankoAuthElement) {
925
- this.log("Event listeners already attached to this element");
926
938
  return;
927
939
  }
928
-
940
+ // no exports available for adding css, so injecting it
929
941
  if (hankoAuth) {
930
942
  this._currentHankoAuthElement = hankoAuth;
931
- this.log("Attaching event listeners to hanko-auth element");
943
+ const hankoShadow = (hankoAuth as HTMLElement & { shadowRoot: ShadowRoot | null }).shadowRoot;
944
+ if (hankoShadow && !hankoShadow.querySelector("#hot-hanko-overrides")) {
945
+ const style = document.createElement("style");
946
+ style.id = "hot-hanko-overrides";
947
+ style.textContent = `
948
+ .hanko_lastUsed { margin-left: 8px; }
949
+ .hanko_form .hanko_li { min-width: 100%; }
950
+ `;
951
+ hankoShadow.appendChild(style);
952
+ }
953
+
954
+ this._setupSignUpSubtitleObserver(hankoAuth);
932
955
 
933
956
  hankoAuth.addEventListener("onSessionCreated", (e: any) => {
934
957
  this.log(`Hanko event: onSessionCreated`, e.detail);
@@ -949,6 +972,62 @@ export class HankoAuth extends LitElement {
949
972
  }
950
973
  });
951
974
  }
975
+ // subtitle handling
976
+ private _setupSignUpSubtitleObserver(hankoAuth: Element) {
977
+ const injectSubtitle = () => {
978
+ const hankoShadow = (hankoAuth as HTMLElement & { shadowRoot: ShadowRoot | null }).shadowRoot;
979
+ if (!hankoShadow) return;
980
+
981
+ const h1 = hankoShadow.querySelector<HTMLElement>("h1[part='headline1']");
982
+ const headlineText = h1?.textContent?.trim() ?? "";
983
+
984
+ const existing = hankoShadow.querySelector(".hot-subtitle");
985
+
986
+ const isSignUp = this._signUpHeadlines.has(headlineText);
987
+ const isLogin = this._loginHeadlines.has(headlineText);
988
+
989
+ if (!isSignUp && !isLogin) {
990
+ if (existing) {
991
+ this._hankoObserver?.disconnect();
992
+ existing.remove();
993
+ this._hankoObserver?.observe(hankoShadow, { childList: true, subtree: true });
994
+ }
995
+ return;
996
+ }
997
+
998
+ const subtitleText = isSignUp
999
+ ? this.t("signUpSubtitle")
1000
+ : this.t("loginSubtitle");
1001
+
1002
+ if (existing && existing.textContent === subtitleText) return;
1003
+ if (!h1) return;
1004
+
1005
+ this._hankoObserver?.disconnect();
1006
+
1007
+ if (existing) existing.remove();
1008
+
1009
+ const subtitle = document.createElement("p");
1010
+ subtitle.className = "hot-subtitle";
1011
+ subtitle.textContent = subtitleText;
1012
+ subtitle.style.cssText =
1013
+ "margin: -4px 0 16px; text-align: center; font-size: var(--hot-font-size-large); color: var(--hot-color-gray-600, #6b7280); font-weight: normal;";
1014
+
1015
+ h1.insertAdjacentElement("afterend", subtitle);
1016
+
1017
+ this._hankoObserver?.observe(hankoShadow, { childList: true, subtree: true });
1018
+ };
1019
+
1020
+ if (this._hankoObserver) {
1021
+ this._hankoObserver.disconnect();
1022
+ }
1023
+
1024
+ const hankoShadow = (hankoAuth as HTMLElement & { shadowRoot: ShadowRoot | null }).shadowRoot;
1025
+ if (hankoShadow) {
1026
+ this._hankoObserver = new MutationObserver(() => injectSubtitle());
1027
+ this._hankoObserver.observe(hankoShadow, { childList: true, subtree: true });
1028
+ injectSubtitle();
1029
+ }
1030
+ }
952
1031
 
953
1032
  private async handleHankoSuccess(event: any) {
954
1033
  this.log("Hanko auth success:", event.detail);
@@ -1444,7 +1523,6 @@ window.location.href = redirectUrl;
1444
1523
  <div class="osm-section">
1445
1524
  <div class="osm-connected">
1446
1525
  <div class="osm-badge">
1447
- <span class="osm-badge-icon">🗺️</span>
1448
1526
  <div>
1449
1527
  <div>${this.t("connectedToOpenStreetMap")}</div>
1450
1528
  ${this.osmData?.osm_username
@@ -1633,7 +1711,7 @@ window.location.href = redirectUrl;
1633
1711
  --color: var(--hot-color-gray-900);
1634
1712
  --color-shade-1: var(--hot-color-gray-700);
1635
1713
  --color-shade-2: var(--hot-color-gray-100);
1636
- --brand-color: var(--hot-color-gray-800);
1714
+ --brand-color: var(--hot-color-gray-1000);
1637
1715
  --brand-color-shade-1: var(--hot-color-gray-900);
1638
1716
  --brand-contrast-color: white;
1639
1717
  --background-color: white;
@@ -1645,7 +1723,7 @@ window.location.href = redirectUrl;
1645
1723
  --item-height: 2.75rem;
1646
1724
  --item-margin: var(--hot-spacing-small) 0;
1647
1725
  --container-padding: 0;
1648
- --headline1-font-size: var(--hot-font-size-large);
1726
+ --headline1-font-size: var(--hot-font-size-xl);
1649
1727
  --headline1-font-weight: var(--hot-font-weight-semibold);
1650
1728
  --headline2-font-size: var(--hot-font-size-medium);
1651
1729
  --headline2-font-weight: var(--hot-font-weight-semibold);
@@ -1653,7 +1731,7 @@ window.location.href = redirectUrl;
1653
1731
  >
1654
1732
  ${keyed(
1655
1733
  this.lang,
1656
- html`<hanko-auth lang="${this.lang}"></hanko-auth>`,
1734
+ html`<hanko-auth lang="${this.lang}" exportparts="link"></hanko-auth>`,
1657
1735
  )}
1658
1736
  </div>
1659
1737
  `;
@@ -1698,5 +1776,5 @@ declare global {
1698
1776
  }
1699
1777
  }
1700
1778
 
1701
- // Re-export Hanko translations for use by consuming apps
1702
- export { en, es, fr, pt };
1779
+ // Re-export for use by consuming apps
1780
+ 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: "Sign up here",
13
+ alreadyHaveAnAccount: "Already have a HOT account?",
14
+ dontHaveAnAccount: "Don't have a HOT account?",
15
+ },
16
+ texts: {
17
+ enterPasscode:
18
+ "Please enter below the passcode we’ve sent to your email address:",
19
+ },
20
+ };
@@ -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: "La aplicación de autenticación está configurada",
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: 'Ingrese el código que se envió a "{emailAddress}".',
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:
@@ -119,7 +120,7 @@ export const es = {
119
120
  signInPasskey: "Iniciar sesión con llave de acceso",
120
121
  registerAuthenticator: "Crear una llave de acceso",
121
122
  signIn: "Iniciar sesión",
122
- signUp: "Crear cuenta",
123
+ signUp: "Regístrese aquí",
123
124
  sendNewPasscode: "Enviar nuevo código",
124
125
  passwordRetryAfter: "Reintentar en {passwordRetryAfter}",
125
126
  passcodeResendAfter: "Solicitar nuevo código en {passcodeResendAfter}",
@@ -141,7 +142,7 @@ export const es = {
141
142
  emailOrUsername: "Correo o nombre de usuario",
142
143
  username: "Nombre de usuario",
143
144
  optional: "opcional",
144
- dontHaveAnAccount: "¿No tiene una cuenta?",
145
+ dontHaveAnAccount: "¿No tiene una cuenta HOT?",
145
146
  alreadyHaveAnAccount: "¿Ya tiene una cuenta?",
146
147
  changeUsername: "Cambiar nombre de usuario",
147
148
  setUsername: "Establecer nombre de usuario",
@@ -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:
@@ -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: "L'application d'authentification est configurée",
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: 'Entrez le code envoyé à "{emailAddress}".',
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:
@@ -119,7 +120,7 @@ export const fr = {
119
120
  signInPasskey: "Se connecter avec clé d'accès",
120
121
  registerAuthenticator: "Créer une clé d'accès",
121
122
  signIn: "Se connecter",
122
- signUp: "Créer un compte",
123
+ signUp: "S'inscrire ici",
123
124
  sendNewPasscode: "Envoyer un nouveau code",
124
125
  passwordRetryAfter: "Réessayer dans {passwordRetryAfter}",
125
126
  passcodeResendAfter: "Demander un nouveau code dans {passcodeResendAfter}",
@@ -141,7 +142,7 @@ export const fr = {
141
142
  emailOrUsername: "E-mail ou nom d'utilisateur",
142
143
  username: "Nom d'utilisateur",
143
144
  optional: "optionnel",
144
- dontHaveAnAccount: "Vous n'avez pas de compte ?",
145
+ dontHaveAnAccount: "Vous n'avez pas de compte HOT ?",
145
146
  alreadyHaveAnAccount: "Vous avez déjà un compte ?",
146
147
  changeUsername: "Changer le nom d'utilisateur",
147
148
  setUsername: "Définir le nom d'utilisateur",
@@ -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:
@@ -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: "O aplicativo de autenticação está configurado",
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: 'Digite o código enviado para "{emailAddress}".',
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:
@@ -119,7 +119,7 @@ export const pt = {
119
119
  signInPasskey: "Entrar com chave de acesso",
120
120
  registerAuthenticator: "Criar uma chave de acesso",
121
121
  signIn: "Entrar",
122
- signUp: "Criar conta",
122
+ signUp: "Cadastre-se aqui",
123
123
  sendNewPasscode: "Enviar novo código",
124
124
  passwordRetryAfter: "Tentar novamente em {passwordRetryAfter}",
125
125
  passcodeResendAfter: "Solicitar novo código em {passcodeResendAfter}",
@@ -141,7 +141,7 @@ export const pt = {
141
141
  emailOrUsername: "E-mail ou nome de usuário",
142
142
  username: "Nome de usuário",
143
143
  optional: "opcional",
144
- dontHaveAnAccount: "Não tem uma conta?",
144
+ dontHaveAnAccount: "Não tem uma conta HOT?",
145
145
  alreadyHaveAnAccount: "Já tem uma conta?",
146
146
  changeUsername: "Alterar nome de usuário",
147
147
  setUsername: "Definir nome de usuário",
@@ -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,30 @@
1
+ // Hanko's UI overwrites
2
+ import { en } from "@teamhanko/hanko-elements/i18n/en";
3
+ import { fr as hankoFr } from "@teamhanko/hanko-elements/i18n/fr";
4
+ import { enOverrides } from "./hanko-i18n-en";
5
+ import { es as esOverrides } from "./hanko-i18n-es";
6
+ import { fr as frOverrides } from "./hanko-i18n-fr";
7
+ import { pt as ptOverrides } 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
+ const fr = JSON.parse(JSON.stringify(hankoFr));
14
+ Object.assign(fr.headlines, frOverrides.headlines);
15
+ Object.assign(fr.labels, frOverrides.labels);
16
+ Object.assign(fr.texts, frOverrides.texts);
17
+
18
+ const es = JSON.parse(JSON.stringify(en));
19
+ Object.assign(es.headlines, esOverrides.headlines);
20
+ Object.assign(es.labels, esOverrides.labels);
21
+ Object.assign(es.texts, esOverrides.texts);
22
+
23
+ const pt = JSON.parse(JSON.stringify(en));
24
+ Object.assign(pt.headlines, ptOverrides.headlines);
25
+ Object.assign(pt.labels, ptOverrides.labels);
26
+ Object.assign(pt.texts, ptOverrides.texts);
27
+
28
+ export function getTranslations() {
29
+ return { en, es, fr, pt };
30
+ }
@@ -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
  };