@zoreal/oauth2-js 0.1.6 → 0.1.8

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/index.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  DEFAULT_ISSUER: () => DEFAULT_ISSUER,
24
+ DEFAULT_PAIRING_TIMEOUT_MS: () => DEFAULT_PAIRING_TIMEOUT_MS,
24
25
  FlowAbandonedError: () => FlowAbandonedError,
25
26
  OAuthFlowError: () => OAuthFlowError,
26
27
  POLL_INTERVAL_ENROLLING_MS: () => POLL_INTERVAL_ENROLLING_MS,
@@ -33,6 +34,7 @@ __export(index_exports, {
33
34
  generateState: () => generateState,
34
35
  generateVerifier: () => generateVerifier,
35
36
  isMobileUserAgent: () => isMobileUserAgent,
37
+ mountPairingModal: () => mountPairingModal,
36
38
  pollUntilApproved: () => pollUntilApproved,
37
39
  startLogin: () => startLogin,
38
40
  startPairing: () => startPairing,
@@ -56,7 +58,7 @@ function unsafeClaims(idToken) {
56
58
 
57
59
  // src/wire.ts
58
60
  var WIRE_VERSION = 1;
59
- var SDK_VERSION = "0.1.6";
61
+ var SDK_VERSION = "0.1.8";
60
62
  var SDK_NAME = "@zoreal/oauth2-js";
61
63
  var DEFAULT_ISSUER = "https://id.zoreal.com";
62
64
  var POLL_INTERVAL_MS = 2e3;
@@ -83,7 +85,7 @@ async function parseJson(response) {
83
85
  return {};
84
86
  }
85
87
  }
86
- async function startPairing(issuer, params) {
88
+ async function startPairing(issuer, params, signal) {
87
89
  const response = await fetch(`${issuer}/pair`, {
88
90
  method: "POST",
89
91
  headers: { "Content-Type": "application/json" },
@@ -92,7 +94,8 @@ async function startPairing(issuer, params) {
92
94
  code_challenge_method: "S256",
93
95
  wire_version: WIRE_VERSION,
94
96
  sdk: `${SDK_NAME}/${SDK_VERSION}`
95
- })
97
+ }),
98
+ signal
96
99
  });
97
100
  const body = await parseJson(response);
98
101
  if (!response.ok) {
@@ -179,6 +182,1174 @@ function isMobileUserAgent() {
179
182
  return /android|iphone|ipad|ipod/i.test(navigator.userAgent);
180
183
  }
181
184
 
185
+ // src/i18n.ts
186
+ var en = {
187
+ title: "Scan to sign in",
188
+ titleApprove: "Approve on your phone",
189
+ bodyScan: "Scan with your phone camera or the ZOREAL ID app.",
190
+ bodyApprove: "Approve the login in your ZOREAL ID app.",
191
+ bodyEnrolling: "Finish setting up ZOREAL ID on your phone, then approve the login.",
192
+ waiting: "Waiting for scan",
193
+ waitingApproval: "Waiting for approval",
194
+ expiresIn: "Expires in {time}",
195
+ secured: "Proof-of-Human verification by ZOREAL",
196
+ noIdTitle: "No ZOREAL ID yet?",
197
+ noIdBody: "Scan the same code to download the app and create one for free. It only takes a minute.",
198
+ cancel: "Cancel",
199
+ close: "Close",
200
+ qrAlt: "QR code to sign in with ZOREAL"
201
+ };
202
+ var TRANSLATIONS = {
203
+ en,
204
+ sv: {
205
+ title: "Skanna f\xF6r att logga in",
206
+ titleApprove: "Godk\xE4nn p\xE5 telefonen",
207
+ bodyScan: "Skanna med telefonens kamera eller ZOREAL ID-appen.",
208
+ bodyApprove: "Godk\xE4nn inloggningen i ZOREAL ID-appen.",
209
+ bodyEnrolling: "Slutf\xF6r konfigurationen av ZOREAL ID p\xE5 telefonen och godk\xE4nn sedan inloggningen.",
210
+ waiting: "V\xE4ntar p\xE5 skanning",
211
+ waitingApproval: "V\xE4ntar p\xE5 godk\xE4nnande",
212
+ expiresIn: "Upph\xF6r om {time}",
213
+ secured: "Proof-of-Human-verifiering av ZOREAL",
214
+ noIdTitle: "Har du inget ZOREAL ID?",
215
+ noIdBody: "Skanna samma kod f\xF6r att ladda ner appen och skapa ett gratis. Det tar bara en minut.",
216
+ cancel: "Avbryt",
217
+ close: "St\xE4ng",
218
+ qrAlt: "QR-kod f\xF6r att logga in med ZOREAL"
219
+ },
220
+ es: {
221
+ title: "Escanea para iniciar sesi\xF3n",
222
+ titleApprove: "Apru\xE9balo en tu tel\xE9fono",
223
+ bodyScan: "Escanea con la c\xE1mara de tu tel\xE9fono o con la app ZOREAL ID.",
224
+ bodyApprove: "Aprueba el inicio de sesi\xF3n en tu app ZOREAL ID.",
225
+ bodyEnrolling: "Termina de configurar ZOREAL ID en tu tel\xE9fono y luego aprueba el inicio de sesi\xF3n.",
226
+ waiting: "Esperando el escaneo",
227
+ waitingApproval: "Esperando aprobaci\xF3n",
228
+ expiresIn: "Caduca en {time}",
229
+ secured: "Verificaci\xF3n Proof-of-Human de ZOREAL",
230
+ noIdTitle: "\xBFA\xFAn no tienes ZOREAL ID?",
231
+ noIdBody: "Escanea el mismo c\xF3digo para descargar la app y crear una gratis. Solo toma un minuto.",
232
+ cancel: "Cancelar",
233
+ close: "Cerrar",
234
+ qrAlt: "C\xF3digo QR para iniciar sesi\xF3n con ZOREAL"
235
+ },
236
+ pt: {
237
+ title: "Digitalize para entrar",
238
+ titleApprove: "Aprove no seu telefone",
239
+ bodyScan: "Digitalize com a c\xE2mara do seu telefone ou com a app ZOREAL ID.",
240
+ bodyApprove: "Aprove o login no app ZOREAL ID.",
241
+ bodyEnrolling: "Termine de configurar o ZOREAL ID no seu telefone e depois aprove o login.",
242
+ waiting: "Aguardando digitaliza\xE7\xE3o",
243
+ waitingApproval: "Aguardando aprova\xE7\xE3o",
244
+ expiresIn: "Expira em {time}",
245
+ secured: "Verifica\xE7\xE3o Proof-of-Human da ZOREAL",
246
+ noIdTitle: "Ainda n\xE3o tem ZOREAL ID?",
247
+ noIdBody: "Digitalize o mesmo c\xF3digo para baixar o app e criar uma conta gr\xE1tis. Leva s\xF3 um minuto.",
248
+ cancel: "Cancelar",
249
+ close: "Fechar",
250
+ qrAlt: "C\xF3digo QR para entrar com ZOREAL"
251
+ },
252
+ fr: {
253
+ title: "Scannez pour vous connecter",
254
+ titleApprove: "Approuvez sur votre t\xE9l\xE9phone",
255
+ bodyScan: "Scannez avec l'appareil photo de votre t\xE9l\xE9phone ou l'app ZOREAL ID.",
256
+ bodyApprove: "Approuvez la connexion dans votre app ZOREAL ID.",
257
+ bodyEnrolling: "Terminez la configuration de ZOREAL ID sur votre t\xE9l\xE9phone, puis approuvez la connexion.",
258
+ waiting: "En attente du scan",
259
+ waitingApproval: "En attente d'approbation",
260
+ expiresIn: "Expire dans {time}",
261
+ secured: "V\xE9rification Proof-of-Human par ZOREAL",
262
+ noIdTitle: "Pas encore de ZOREAL ID ?",
263
+ noIdBody: "Scannez le m\xEAme code pour t\xE9l\xE9charger l'app et en cr\xE9er un gratuitement. Cela prend une minute.",
264
+ cancel: "Annuler",
265
+ close: "Fermer",
266
+ qrAlt: "Code QR pour se connecter avec ZOREAL"
267
+ },
268
+ de: {
269
+ title: "Zum Anmelden scannen",
270
+ titleApprove: "Auf dem Handy best\xE4tigen",
271
+ bodyScan: "Mit der Handykamera oder der ZOREAL ID App scannen.",
272
+ bodyApprove: "Anmeldung in der ZOREAL ID App best\xE4tigen.",
273
+ bodyEnrolling: "ZOREAL ID auf dem Handy fertig einrichten und dann die Anmeldung best\xE4tigen.",
274
+ waiting: "Warten auf Scan",
275
+ waitingApproval: "Warten auf Best\xE4tigung",
276
+ expiresIn: "L\xE4uft ab in {time}",
277
+ secured: "Proof-of-Human-Verifizierung von ZOREAL",
278
+ noIdTitle: "Noch keine ZOREAL ID?",
279
+ noIdBody: "Denselben Code scannen, um die App zu laden und kostenlos eine zu erstellen. Dauert nur eine Minute.",
280
+ cancel: "Abbrechen",
281
+ close: "Schlie\xDFen",
282
+ qrAlt: "QR-Code f\xFCr die Anmeldung mit ZOREAL"
283
+ },
284
+ ru: {
285
+ title: "\u041E\u0442\u0441\u043A\u0430\u043D\u0438\u0440\u0443\u0439\u0442\u0435, \u0447\u0442\u043E\u0431\u044B \u0432\u043E\u0439\u0442\u0438",
286
+ titleApprove: "\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0435 \u043D\u0430 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0435",
287
+ bodyScan: "\u041E\u0442\u0441\u043A\u0430\u043D\u0438\u0440\u0443\u0439\u0442\u0435 \u043A\u0430\u043C\u0435\u0440\u043E\u0439 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430 \u0438\u043B\u0438 \u0447\u0435\u0440\u0435\u0437 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 ZOREAL ID.",
288
+ bodyApprove: "\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0435 \u0432\u0445\u043E\u0434 \u0432 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0438 ZOREAL ID.",
289
+ bodyEnrolling: "\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0435 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0443 ZOREAL ID \u043D\u0430 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0435, \u0437\u0430\u0442\u0435\u043C \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0435 \u0432\u0445\u043E\u0434.",
290
+ waiting: "\u041E\u0436\u0438\u0434\u0430\u043D\u0438\u0435 \u0441\u043A\u0430\u043D\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F",
291
+ waitingApproval: "\u041E\u0436\u0438\u0434\u0430\u043D\u0438\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F",
292
+ expiresIn: "\u0418\u0441\u0442\u0435\u043A\u0430\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 {time}",
293
+ secured: "\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 Proof-of-Human \u043E\u0442 ZOREAL",
294
+ noIdTitle: "\u0415\u0449\u0451 \u043D\u0435\u0442 ZOREAL ID?",
295
+ noIdBody: "\u041E\u0442\u0441\u043A\u0430\u043D\u0438\u0440\u0443\u0439\u0442\u0435 \u0442\u043E\u0442 \u0436\u0435 \u043A\u043E\u0434, \u0447\u0442\u043E\u0431\u044B \u0441\u043A\u0430\u0447\u0430\u0442\u044C \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0438 \u0441\u043E\u0437\u0434\u0430\u0442\u044C \u0435\u0433\u043E \u0431\u0435\u0441\u043F\u043B\u0430\u0442\u043D\u043E. \u042D\u0442\u043E \u0437\u0430\u0439\u043C\u0451\u0442 \u043C\u0438\u043D\u0443\u0442\u0443.",
296
+ cancel: "\u041E\u0442\u043C\u0435\u043D\u0430",
297
+ close: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C",
298
+ qrAlt: "QR-\u043A\u043E\u0434 \u0434\u043B\u044F \u0432\u0445\u043E\u0434\u0430 \u0447\u0435\u0440\u0435\u0437 ZOREAL"
299
+ },
300
+ ja: {
301
+ title: "\u30B9\u30AD\u30E3\u30F3\u3057\u3066\u30ED\u30B0\u30A4\u30F3",
302
+ titleApprove: "\u30B9\u30DE\u30FC\u30C8\u30D5\u30A9\u30F3\u3067\u627F\u8A8D",
303
+ bodyScan: "\u30B9\u30DE\u30FC\u30C8\u30D5\u30A9\u30F3\u306E\u30AB\u30E1\u30E9\u307E\u305F\u306FZOREAL ID\u30A2\u30D7\u30EA\u3067\u30B9\u30AD\u30E3\u30F3\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
304
+ bodyApprove: "ZOREAL ID\u30A2\u30D7\u30EA\u3067\u30ED\u30B0\u30A4\u30F3\u3092\u627F\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
305
+ bodyEnrolling: "\u30B9\u30DE\u30FC\u30C8\u30D5\u30A9\u30F3\u3067ZOREAL ID\u306E\u8A2D\u5B9A\u3092\u5B8C\u4E86\u3057\u3001\u30ED\u30B0\u30A4\u30F3\u3092\u627F\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
306
+ waiting: "\u30B9\u30AD\u30E3\u30F3\u5F85\u3061",
307
+ waitingApproval: "\u627F\u8A8D\u5F85\u3061",
308
+ expiresIn: "\u6709\u52B9\u671F\u9650\u307E\u3067 {time}",
309
+ secured: "ZOREAL\u306B\u3088\u308BProof-of-Human\u8A8D\u8A3C",
310
+ noIdTitle: "ZOREAL ID\u3092\u304A\u6301\u3061\u3067\u306A\u3044\u3067\u3059\u304B\uFF1F",
311
+ noIdBody: "\u540C\u3058\u30B3\u30FC\u30C9\u3092\u30B9\u30AD\u30E3\u30F3\u3057\u3066\u30A2\u30D7\u30EA\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3057\u3001\u7121\u6599\u3067\u4F5C\u6210\u3067\u304D\u307E\u3059\u30021\u5206\u307B\u3069\u3067\u5B8C\u4E86\u3057\u307E\u3059\u3002",
312
+ cancel: "\u30AD\u30E3\u30F3\u30BB\u30EB",
313
+ close: "\u9589\u3058\u308B",
314
+ qrAlt: "ZOREAL\u3067\u30ED\u30B0\u30A4\u30F3\u3059\u308B\u305F\u3081\u306EQR\u30B3\u30FC\u30C9"
315
+ },
316
+ hi: {
317
+ title: "\u0938\u093E\u0907\u0928 \u0907\u0928 \u0915\u0930\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F \u0938\u094D\u0915\u0948\u0928 \u0915\u0930\u0947\u0902",
318
+ titleApprove: "\u0905\u092A\u0928\u0947 \u092B\u094B\u0928 \u092A\u0930 \u0938\u094D\u0935\u0940\u0915\u0943\u0924 \u0915\u0930\u0947\u0902",
319
+ bodyScan: "\u0905\u092A\u0928\u0947 \u092B\u094B\u0928 \u0915\u0947 \u0915\u0948\u092E\u0930\u0947 \u092F\u093E ZOREAL ID \u0910\u092A \u0938\u0947 \u0938\u094D\u0915\u0948\u0928 \u0915\u0930\u0947\u0902\u0964",
320
+ bodyApprove: "\u0905\u092A\u0928\u0947 ZOREAL ID \u0910\u092A \u092E\u0947\u0902 \u0932\u0949\u0917\u093F\u0928 \u0938\u094D\u0935\u0940\u0915\u0943\u0924 \u0915\u0930\u0947\u0902\u0964",
321
+ bodyEnrolling: "\u0905\u092A\u0928\u0947 \u092B\u094B\u0928 \u092A\u0930 ZOREAL ID \u0938\u0947\u091F\u0905\u092A \u092A\u0942\u0930\u093E \u0915\u0930\u0947\u0902, \u092B\u093F\u0930 \u0932\u0949\u0917\u093F\u0928 \u0938\u094D\u0935\u0940\u0915\u0943\u0924 \u0915\u0930\u0947\u0902\u0964",
322
+ waiting: "\u0938\u094D\u0915\u0948\u0928 \u0915\u0940 \u092A\u094D\u0930\u0924\u0940\u0915\u094D\u0937\u093E \u0939\u0948",
323
+ waitingApproval: "\u0938\u094D\u0935\u0940\u0915\u0943\u0924\u093F \u0915\u0940 \u092A\u094D\u0930\u0924\u0940\u0915\u094D\u0937\u093E \u0939\u0948",
324
+ expiresIn: "{time} \u092E\u0947\u0902 \u0938\u092E\u093E\u092A\u094D\u0924",
325
+ secured: "ZOREAL \u0926\u094D\u0935\u093E\u0930\u093E Proof-of-Human \u0938\u0924\u094D\u092F\u093E\u092A\u0928",
326
+ noIdTitle: "\u0905\u092D\u0940 \u0924\u0915 ZOREAL ID \u0928\u0939\u0940\u0902 \u0939\u0948?",
327
+ noIdBody: "\u0910\u092A \u0921\u093E\u0909\u0928\u0932\u094B\u0921 \u0915\u0930\u0928\u0947 \u0914\u0930 \u092E\u0941\u092B\u094D\u0924 \u092E\u0947\u0902 \u090F\u0915 \u092C\u0928\u093E\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F \u0935\u0939\u0940 \u0915\u094B\u0921 \u0938\u094D\u0915\u0948\u0928 \u0915\u0930\u0947\u0902\u0964 \u0907\u0938\u092E\u0947\u0902 \u092C\u0938 \u090F\u0915 \u092E\u093F\u0928\u091F \u0932\u0917\u0924\u093E \u0939\u0948\u0964",
328
+ cancel: "\u0930\u0926\u094D\u0926 \u0915\u0930\u0947\u0902",
329
+ close: "\u092C\u0902\u0926 \u0915\u0930\u0947\u0902",
330
+ qrAlt: "ZOREAL \u0938\u0947 \u0938\u093E\u0907\u0928 \u0907\u0928 \u0915\u0930\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F QR \u0915\u094B\u0921"
331
+ },
332
+ zhs: {
333
+ title: "\u626B\u7801\u767B\u5F55",
334
+ titleApprove: "\u5728\u624B\u673A\u4E0A\u6279\u51C6",
335
+ bodyScan: "\u4F7F\u7528\u624B\u673A\u76F8\u673A\u6216 ZOREAL ID \u5E94\u7528\u626B\u63CF\u3002",
336
+ bodyApprove: "\u8BF7\u5728 ZOREAL ID \u5E94\u7528\u4E2D\u6279\u51C6\u767B\u5F55\u3002",
337
+ bodyEnrolling: "\u8BF7\u5728\u624B\u673A\u4E0A\u5B8C\u6210 ZOREAL ID \u8BBE\u7F6E\uFF0C\u7136\u540E\u6279\u51C6\u767B\u5F55\u3002",
338
+ waiting: "\u7B49\u5F85\u626B\u63CF",
339
+ waitingApproval: "\u7B49\u5F85\u6279\u51C6",
340
+ expiresIn: "{time} \u540E\u5931\u6548",
341
+ secured: "\u7531 ZOREAL \u63D0\u4F9B\u7684 Proof-of-Human \u9A8C\u8BC1",
342
+ noIdTitle: "\u8FD8\u6CA1\u6709 ZOREAL ID\uFF1F",
343
+ noIdBody: "\u626B\u63CF\u540C\u4E00\u4E2A\u4E8C\u7EF4\u7801\u5373\u53EF\u4E0B\u8F7D\u5E94\u7528\u5E76\u514D\u8D39\u521B\u5EFA\uFF0C\u53EA\u9700\u4E00\u5206\u949F\u3002",
344
+ cancel: "\u53D6\u6D88",
345
+ close: "\u5173\u95ED",
346
+ qrAlt: "\u4F7F\u7528 ZOREAL \u767B\u5F55\u7684\u4E8C\u7EF4\u7801"
347
+ },
348
+ zht: {
349
+ title: "\u6383\u78BC\u767B\u5165",
350
+ titleApprove: "\u5728\u624B\u6A5F\u4E0A\u6838\u51C6",
351
+ bodyScan: "\u4F7F\u7528\u624B\u6A5F\u76F8\u6A5F\u6216 ZOREAL ID \u61C9\u7528\u7A0B\u5F0F\u6383\u63CF\u3002",
352
+ bodyApprove: "\u8ACB\u5728 ZOREAL ID \u61C9\u7528\u7A0B\u5F0F\u4E2D\u6838\u51C6\u767B\u5165\u3002",
353
+ bodyEnrolling: "\u8ACB\u5728\u624B\u6A5F\u4E0A\u5B8C\u6210 ZOREAL ID \u8A2D\u5B9A\uFF0C\u7136\u5F8C\u6838\u51C6\u767B\u5165\u3002",
354
+ waiting: "\u7B49\u5F85\u6383\u63CF",
355
+ waitingApproval: "\u7B49\u5F85\u6838\u51C6",
356
+ expiresIn: "{time} \u5F8C\u5931\u6548",
357
+ secured: "\u7531 ZOREAL \u63D0\u4F9B\u7684 Proof-of-Human \u9A57\u8B49",
358
+ noIdTitle: "\u9084\u6C92\u6709 ZOREAL ID\uFF1F",
359
+ noIdBody: "\u6383\u63CF\u540C\u4E00\u500B QR code \u5373\u53EF\u4E0B\u8F09\u61C9\u7528\u7A0B\u5F0F\u4E26\u514D\u8CBB\u5EFA\u7ACB\uFF0C\u53EA\u9700\u4E00\u5206\u9418\u3002",
360
+ cancel: "\u53D6\u6D88",
361
+ close: "\u95DC\u9589",
362
+ qrAlt: "\u4F7F\u7528 ZOREAL \u767B\u5165\u7684 QR code"
363
+ },
364
+ ar: {
365
+ title: "\u0627\u0645\u0633\u062D \u0644\u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u062F\u062E\u0648\u0644",
366
+ titleApprove: "\u0648\u0627\u0641\u0642 \u0639\u0644\u0649 \u0647\u0627\u062A\u0641\u0643",
367
+ bodyScan: "\u0627\u0645\u0633\u062D \u0628\u0627\u0633\u062A\u062E\u062F\u0627\u0645 \u0643\u0627\u0645\u064A\u0631\u0627 \u0647\u0627\u062A\u0641\u0643 \u0623\u0648 \u062A\u0637\u0628\u064A\u0642 ZOREAL ID.",
368
+ bodyApprove: "\u0648\u0627\u0641\u0642 \u0639\u0644\u0649 \u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u062F\u062E\u0648\u0644 \u0641\u064A \u062A\u0637\u0628\u064A\u0642 ZOREAL ID.",
369
+ bodyEnrolling: "\u0623\u0643\u0645\u0644 \u0625\u0639\u062F\u0627\u062F ZOREAL ID \u0639\u0644\u0649 \u0647\u0627\u062A\u0641\u0643\u060C \u062B\u0645 \u0648\u0627\u0641\u0642 \u0639\u0644\u0649 \u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u062F\u062E\u0648\u0644.",
370
+ waiting: "\u0641\u064A \u0627\u0646\u062A\u0638\u0627\u0631 \u0627\u0644\u0645\u0633\u062D",
371
+ waitingApproval: "\u0641\u064A \u0627\u0646\u062A\u0638\u0627\u0631 \u0627\u0644\u0645\u0648\u0627\u0641\u0642\u0629",
372
+ expiresIn: "\u062A\u0646\u062A\u0647\u064A \u0627\u0644\u0635\u0644\u0627\u062D\u064A\u0629 \u062E\u0644\u0627\u0644 {time}",
373
+ secured: "\u0627\u0644\u062A\u062D\u0642\u0642 \u0645\u0646 Proof-of-Human \u0628\u0648\u0627\u0633\u0637\u0629 ZOREAL",
374
+ noIdTitle: "\u0644\u064A\u0633 \u0644\u062F\u064A\u0643 ZOREAL ID \u0628\u0639\u062F\u061F",
375
+ noIdBody: "\u0627\u0645\u0633\u062D \u0627\u0644\u0631\u0645\u0632 \u0646\u0641\u0633\u0647 \u0644\u062A\u0646\u0632\u064A\u0644 \u0627\u0644\u062A\u0637\u0628\u064A\u0642 \u0648\u0625\u0646\u0634\u0627\u0621 \u062D\u0633\u0627\u0628 \u0645\u062C\u0627\u0646\u064A. \u064A\u0633\u062A\u063A\u0631\u0642 \u0627\u0644\u0623\u0645\u0631 \u062F\u0642\u064A\u0642\u0629 \u0648\u0627\u062D\u062F\u0629 \u0641\u0642\u0637.",
376
+ cancel: "\u0625\u0644\u063A\u0627\u0621",
377
+ close: "\u0625\u063A\u0644\u0627\u0642",
378
+ qrAlt: "\u0631\u0645\u0632 QR \u0644\u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u062F\u062E\u0648\u0644 \u0628\u0627\u0633\u062A\u062E\u062F\u0627\u0645 ZOREAL"
379
+ },
380
+ ko: {
381
+ title: "\uC2A4\uCE94\uD558\uC5EC \uB85C\uADF8\uC778",
382
+ titleApprove: "\uD734\uB300\uD3F0\uC5D0\uC11C \uC2B9\uC778",
383
+ bodyScan: "\uD734\uB300\uD3F0 \uCE74\uBA54\uB77C \uB610\uB294 ZOREAL ID \uC571\uC73C\uB85C \uC2A4\uCE94\uD558\uC138\uC694.",
384
+ bodyApprove: "ZOREAL ID \uC571\uC5D0\uC11C \uB85C\uADF8\uC778\uC744 \uC2B9\uC778\uD558\uC138\uC694.",
385
+ bodyEnrolling: "\uD734\uB300\uD3F0\uC5D0\uC11C ZOREAL ID \uC124\uC815\uC744 \uC644\uB8CC\uD55C \uD6C4 \uB85C\uADF8\uC778\uC744 \uC2B9\uC778\uD558\uC138\uC694.",
386
+ waiting: "\uC2A4\uCE94 \uB300\uAE30 \uC911",
387
+ waitingApproval: "\uC2B9\uC778 \uB300\uAE30 \uC911",
388
+ expiresIn: "{time} \uD6C4 \uB9CC\uB8CC",
389
+ secured: "ZOREAL\uC758 Proof-of-Human \uC778\uC99D",
390
+ noIdTitle: "\uC544\uC9C1 ZOREAL ID\uAC00 \uC5C6\uC73C\uC2E0\uAC00\uC694?",
391
+ noIdBody: "\uAC19\uC740 \uCF54\uB4DC\uB97C \uC2A4\uCE94\uD574 \uC571\uC744 \uB0B4\uB824\uBC1B\uACE0 \uBB34\uB8CC\uB85C \uB9CC\uB4DC\uC138\uC694. 1\uBD84\uC774\uBA74 \uB429\uB2C8\uB2E4.",
392
+ cancel: "\uCDE8\uC18C",
393
+ close: "\uB2EB\uAE30",
394
+ qrAlt: "ZOREAL\uB85C \uB85C\uADF8\uC778\uD558\uAE30 \uC704\uD55C QR \uCF54\uB4DC"
395
+ },
396
+ // Български
397
+ bg: {
398
+ title: "\u0421\u043A\u0430\u043D\u0438\u0440\u0430\u0439\u0442\u0435 \u0437\u0430 \u0432\u0445\u043E\u0434",
399
+ titleApprove: "\u041F\u043E\u0442\u0432\u044A\u0440\u0434\u0435\u0442\u0435 \u043D\u0430 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430 \u0441\u0438",
400
+ bodyScan: "\u0421\u043A\u0430\u043D\u0438\u0440\u0430\u0439\u0442\u0435 \u0441 \u043A\u0430\u043C\u0435\u0440\u0430\u0442\u0430 \u043D\u0430 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430 \u0438\u043B\u0438 \u0441 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435\u0442\u043E ZOREAL ID.",
401
+ bodyApprove: "\u041F\u043E\u0442\u0432\u044A\u0440\u0434\u0435\u0442\u0435 \u0432\u0445\u043E\u0434\u0430 \u0432 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435\u0442\u043E ZOREAL ID.",
402
+ bodyEnrolling: "\u0414\u043E\u0432\u044A\u0440\u0448\u0435\u0442\u0435 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430\u0442\u0430 \u043D\u0430 ZOREAL ID \u043D\u0430 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430 \u0441\u0438, \u0441\u043B\u0435\u0434 \u043A\u043E\u0435\u0442\u043E \u043F\u043E\u0442\u0432\u044A\u0440\u0434\u0435\u0442\u0435 \u0432\u0445\u043E\u0434\u0430.",
403
+ waiting: "\u0418\u0437\u0447\u0430\u043A\u0432\u0430\u043D\u0435 \u043D\u0430 \u0441\u043A\u0430\u043D\u0438\u0440\u0430\u043D\u0435",
404
+ waitingApproval: "\u0418\u0437\u0447\u0430\u043A\u0432\u0430\u043D\u0435 \u043D\u0430 \u043F\u043E\u0442\u0432\u044A\u0440\u0436\u0434\u0435\u043D\u0438\u0435",
405
+ expiresIn: "\u0418\u0437\u0442\u0438\u0447\u0430 \u0441\u043B\u0435\u0434 {time}",
406
+ secured: "\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 Proof-of-Human \u043E\u0442 ZOREAL",
407
+ noIdTitle: "\u0412\u0441\u0435 \u043E\u0449\u0435 \u043D\u044F\u043C\u0430\u0442\u0435 ZOREAL ID?",
408
+ noIdBody: "\u0421\u043A\u0430\u043D\u0438\u0440\u0430\u0439\u0442\u0435 \u0441\u044A\u0449\u0438\u044F \u043A\u043E\u0434, \u0437\u0430 \u0434\u0430 \u0438\u0437\u0442\u0435\u0433\u043B\u0438\u0442\u0435 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435\u0442\u043E \u0438 \u0434\u0430 \u0441\u0438 \u0441\u044A\u0437\u0434\u0430\u0434\u0435\u0442\u0435 \u0431\u0435\u0437\u043F\u043B\u0430\u0442\u0435\u043D \u0430\u043A\u0430\u0443\u043D\u0442. \u041E\u0442\u043D\u0435\u043C\u0430 \u0441\u0430\u043C\u043E \u043C\u0438\u043D\u0443\u0442\u0430.",
409
+ cancel: "\u041E\u0442\u043A\u0430\u0437",
410
+ close: "\u0417\u0430\u0442\u0432\u043E\u0440\u0438",
411
+ qrAlt: "QR \u043A\u043E\u0434 \u0437\u0430 \u0432\u0445\u043E\u0434 \u0441\u044A\u0441 ZOREAL"
412
+ },
413
+ // বাংলা
414
+ bn: {
415
+ title: "\u09B8\u09BE\u0987\u09A8 \u0987\u09A8 \u0995\u09B0\u09A4\u09C7 \u09B8\u09CD\u0995\u09CD\u09AF\u09BE\u09A8 \u0995\u09B0\u09C1\u09A8",
416
+ titleApprove: "\u0986\u09AA\u09A8\u09BE\u09B0 \u09AB\u09CB\u09A8\u09C7 \u0985\u09A8\u09C1\u09AE\u09CB\u09A6\u09A8 \u0995\u09B0\u09C1\u09A8",
417
+ bodyScan: "\u0986\u09AA\u09A8\u09BE\u09B0 \u09AB\u09CB\u09A8\u09C7\u09B0 \u0995\u09CD\u09AF\u09BE\u09AE\u09C7\u09B0\u09BE \u09AC\u09BE ZOREAL ID \u0985\u09CD\u09AF\u09BE\u09AA \u09A6\u09BF\u09AF\u09BC\u09C7 \u09B8\u09CD\u0995\u09CD\u09AF\u09BE\u09A8 \u0995\u09B0\u09C1\u09A8\u0964",
418
+ bodyApprove: "\u0986\u09AA\u09A8\u09BE\u09B0 ZOREAL ID \u0985\u09CD\u09AF\u09BE\u09AA\u09C7 \u09B2\u0997\u0987\u09A8 \u0985\u09A8\u09C1\u09AE\u09CB\u09A6\u09A8 \u0995\u09B0\u09C1\u09A8\u0964",
419
+ bodyEnrolling: "\u0986\u09AA\u09A8\u09BE\u09B0 \u09AB\u09CB\u09A8\u09C7 ZOREAL ID \u09B8\u09C7\u099F\u0986\u09AA \u09B8\u09AE\u09CD\u09AA\u09C2\u09B0\u09CD\u09A3 \u0995\u09B0\u09C1\u09A8, \u09A4\u09BE\u09B0\u09AA\u09B0 \u09B2\u0997\u0987\u09A8 \u0985\u09A8\u09C1\u09AE\u09CB\u09A6\u09A8 \u0995\u09B0\u09C1\u09A8\u0964",
420
+ waiting: "\u09B8\u09CD\u0995\u09CD\u09AF\u09BE\u09A8\u09C7\u09B0 \u0985\u09AA\u09C7\u0995\u09CD\u09B7\u09BE\u09AF\u09BC",
421
+ waitingApproval: "\u0985\u09A8\u09C1\u09AE\u09CB\u09A6\u09A8\u09C7\u09B0 \u0985\u09AA\u09C7\u0995\u09CD\u09B7\u09BE\u09AF\u09BC",
422
+ expiresIn: "{time} \u09AA\u09B0\u09C7 \u09AE\u09C7\u09AF\u09BC\u09BE\u09A6 \u09B6\u09C7\u09B7 \u09B9\u09AC\u09C7",
423
+ secured: "ZOREAL \u09A6\u09CD\u09AC\u09BE\u09B0\u09BE Proof-of-Human \u09AF\u09BE\u099A\u09BE\u0987\u0995\u09B0\u09A3",
424
+ noIdTitle: "\u098F\u0996\u09A8\u09CB ZOREAL ID \u09A8\u09C7\u0987?",
425
+ noIdBody: "\u0985\u09CD\u09AF\u09BE\u09AA \u09A1\u09BE\u0989\u09A8\u09B2\u09CB\u09A1 \u0995\u09B0\u09C7 \u09AC\u09BF\u09A8\u09BE\u09AE\u09C2\u09B2\u09CD\u09AF\u09C7 \u098F\u0995\u099F\u09BF \u09A4\u09C8\u09B0\u09BF \u0995\u09B0\u09A4\u09C7 \u098F\u0995\u0987 \u0995\u09CB\u09A1 \u09B8\u09CD\u0995\u09CD\u09AF\u09BE\u09A8 \u0995\u09B0\u09C1\u09A8\u0964 \u098F\u09A4\u09C7 \u09AE\u09BE\u09A4\u09CD\u09B0 \u098F\u0995 \u09AE\u09BF\u09A8\u09BF\u099F \u09B8\u09AE\u09AF\u09BC \u09B2\u09BE\u0997\u09C7\u0964",
426
+ cancel: "\u09AC\u09BE\u09A4\u09BF\u09B2",
427
+ close: "\u09AC\u09A8\u09CD\u09A7",
428
+ qrAlt: "ZOREAL \u09A6\u09BF\u09AF\u09BC\u09C7 \u09B8\u09BE\u0987\u09A8 \u0987\u09A8 \u0995\u09B0\u09BE\u09B0 \u099C\u09A8\u09CD\u09AF QR \u0995\u09CB\u09A1"
429
+ },
430
+ // Bosanski
431
+ bs: {
432
+ title: "Skenirajte za prijavu",
433
+ titleApprove: "Odobrite na svom telefonu",
434
+ bodyScan: "Skenirajte kamerom svog telefona ili aplikacijom ZOREAL ID.",
435
+ bodyApprove: "Odobrite prijavu u aplikaciji ZOREAL ID.",
436
+ bodyEnrolling: "Zavr\u0161ite pode\u0161avanje ZOREAL ID-a na svom telefonu, a zatim odobrite prijavu.",
437
+ waiting: "\u010Ceka se skeniranje",
438
+ waitingApproval: "\u010Ceka se odobrenje",
439
+ expiresIn: "Isti\u010De za {time}",
440
+ secured: "ZOREAL Proof-of-Human verifikacija",
441
+ noIdTitle: "Nemate ZOREAL ID?",
442
+ noIdBody: "Skenirajte isti kod da preuzmete aplikaciju i besplatno ga napravite. Traje samo minutu.",
443
+ cancel: "Otka\u017Ei",
444
+ close: "Zatvori",
445
+ qrAlt: "QR kod za prijavu putem ZOREAL-a"
446
+ },
447
+ // Čeština
448
+ cs: {
449
+ title: "P\u0159ihlaste se naskenov\xE1n\xEDm",
450
+ titleApprove: "Potvr\u010Fte v telefonu",
451
+ bodyScan: "Naskenujte fotoapar\xE1tem telefonu nebo aplikac\xED ZOREAL ID.",
452
+ bodyApprove: "Potvr\u010Fte p\u0159ihl\xE1\u0161en\xED v aplikaci ZOREAL ID.",
453
+ bodyEnrolling: "Dokon\u010Dete nastaven\xED ZOREAL ID v telefonu a pot\xE9 potvr\u010Fte p\u0159ihl\xE1\u0161en\xED.",
454
+ waiting: "\u010Cek\xE1n\xED na naskenov\xE1n\xED",
455
+ waitingApproval: "\u010Cek\xE1n\xED na potvrzen\xED",
456
+ expiresIn: "Vypr\u0161\xED za {time}",
457
+ secured: "Ov\u011B\u0159en\xED Proof-of-Human od ZOREAL",
458
+ noIdTitle: "Je\u0161t\u011B nem\xE1te ZOREAL ID?",
459
+ noIdBody: "Naskenov\xE1n\xEDm stejn\xE9ho k\xF3du si st\xE1hnete aplikaci a zdarma vytvo\u0159\xEDte ZOREAL ID. Zabere to jen minutu.",
460
+ cancel: "Zru\u0161it",
461
+ close: "Zav\u0159\xEDt",
462
+ qrAlt: "QR k\xF3d pro p\u0159ihl\xE1\u0161en\xED pomoc\xED ZOREAL"
463
+ },
464
+ // Dansk
465
+ da: {
466
+ title: "Scan for at logge ind",
467
+ titleApprove: "Godkend p\xE5 din telefon",
468
+ bodyScan: "Scan med telefonens kamera eller ZOREAL ID-appen.",
469
+ bodyApprove: "Godkend login i din ZOREAL ID-app.",
470
+ bodyEnrolling: "F\xE6rdigg\xF8r ops\xE6tningen af ZOREAL ID p\xE5 din telefon, og godkend derefter login.",
471
+ waiting: "Venter p\xE5 scanning",
472
+ waitingApproval: "Venter p\xE5 godkendelse",
473
+ expiresIn: "Udl\xF8ber om {time}",
474
+ secured: "Proof-of-Human-verificering af ZOREAL",
475
+ noIdTitle: "Har du ikke et ZOREAL ID endnu?",
476
+ noIdBody: "Scan den samme kode for at hente appen og oprette et gratis. Det tager kun et minut.",
477
+ cancel: "Annuller",
478
+ close: "Luk",
479
+ qrAlt: "QR-kode til at logge ind med ZOREAL"
480
+ },
481
+ // Ελληνικά
482
+ el: {
483
+ title: "\u03A3\u03AC\u03C1\u03C9\u03C3\u03B7 \u03B3\u03B9\u03B1 \u03C3\u03CD\u03BD\u03B4\u03B5\u03C3\u03B7",
484
+ titleApprove: "\u0388\u03B3\u03BA\u03C1\u03B9\u03C3\u03B7 \u03B1\u03C0\u03CC \u03C4\u03BF \u03BA\u03B9\u03BD\u03B7\u03C4\u03CC \u03C3\u03B1\u03C2",
485
+ bodyScan: "\u03A3\u03B1\u03C1\u03CE\u03C3\u03C4\u03B5 \u03BC\u03B5 \u03C4\u03B7\u03BD \u03BA\u03AC\u03BC\u03B5\u03C1\u03B1 \u03C4\u03BF\u03C5 \u03BA\u03B9\u03BD\u03B7\u03C4\u03BF\u03CD \u03C3\u03B1\u03C2 \u03AE \u03C4\u03B7\u03BD \u03B5\u03C6\u03B1\u03C1\u03BC\u03BF\u03B3\u03AE ZOREAL ID.",
486
+ bodyApprove: "\u0395\u03B3\u03BA\u03C1\u03AF\u03BD\u03B5\u03C4\u03B5 \u03C4\u03B7 \u03C3\u03CD\u03BD\u03B4\u03B5\u03C3\u03B7 \u03C3\u03C4\u03B7\u03BD \u03B5\u03C6\u03B1\u03C1\u03BC\u03BF\u03B3\u03AE ZOREAL ID.",
487
+ bodyEnrolling: "\u039F\u03BB\u03BF\u03BA\u03BB\u03B7\u03C1\u03CE\u03C3\u03C4\u03B5 \u03C4\u03B7 \u03C1\u03CD\u03B8\u03BC\u03B9\u03C3\u03B7 \u03C4\u03BF\u03C5 ZOREAL ID \u03C3\u03C4\u03BF \u03BA\u03B9\u03BD\u03B7\u03C4\u03CC \u03C3\u03B1\u03C2 \u03BA\u03B1\u03B9 \u03AD\u03C0\u03B5\u03B9\u03C4\u03B1 \u03B5\u03B3\u03BA\u03C1\u03AF\u03BD\u03B5\u03C4\u03B5 \u03C4\u03B7 \u03C3\u03CD\u03BD\u03B4\u03B5\u03C3\u03B7.",
488
+ waiting: "\u0391\u03BD\u03B1\u03BC\u03BF\u03BD\u03AE \u03C3\u03AC\u03C1\u03C9\u03C3\u03B7\u03C2",
489
+ waitingApproval: "\u0391\u03BD\u03B1\u03BC\u03BF\u03BD\u03AE \u03AD\u03B3\u03BA\u03C1\u03B9\u03C3\u03B7\u03C2",
490
+ expiresIn: "\u039B\u03AE\u03B3\u03B5\u03B9 \u03C3\u03B5 {time}",
491
+ secured: "\u0395\u03C0\u03B1\u03BB\u03AE\u03B8\u03B5\u03C5\u03C3\u03B7 Proof-of-Human \u03B1\u03C0\u03CC \u03C4\u03B7 ZOREAL",
492
+ noIdTitle: "\u0394\u03B5\u03BD \u03AD\u03C7\u03B5\u03C4\u03B5 \u03B1\u03BA\u03CC\u03BC\u03B1 ZOREAL ID;",
493
+ noIdBody: "\u03A3\u03B1\u03C1\u03CE\u03C3\u03C4\u03B5 \u03C4\u03BF\u03BD \u03AF\u03B4\u03B9\u03BF \u03BA\u03C9\u03B4\u03B9\u03BA\u03CC \u03B3\u03B9\u03B1 \u03BD\u03B1 \u03BA\u03B1\u03C4\u03B5\u03B2\u03AC\u03C3\u03B5\u03C4\u03B5 \u03C4\u03B7\u03BD \u03B5\u03C6\u03B1\u03C1\u03BC\u03BF\u03B3\u03AE \u03BA\u03B1\u03B9 \u03BD\u03B1 \u03B4\u03B7\u03BC\u03B9\u03BF\u03C5\u03C1\u03B3\u03AE\u03C3\u03B5\u03C4\u03B5 \u03AD\u03BD\u03B1 \u03B4\u03C9\u03C1\u03B5\u03AC\u03BD. \u03A7\u03C1\u03B5\u03B9\u03AC\u03B6\u03B5\u03C4\u03B1\u03B9 \u03BC\u03CC\u03BD\u03BF \u03AD\u03BD\u03B1 \u03BB\u03B5\u03C0\u03C4\u03CC.",
494
+ cancel: "\u0386\u03BA\u03C5\u03C1\u03BF",
495
+ close: "\u039A\u03BB\u03B5\u03AF\u03C3\u03B9\u03BC\u03BF",
496
+ qrAlt: "\u039A\u03C9\u03B4\u03B9\u03BA\u03CC\u03C2 QR \u03B3\u03B9\u03B1 \u03C3\u03CD\u03BD\u03B4\u03B5\u03C3\u03B7 \u03BC\u03B5 ZOREAL"
497
+ },
498
+ // Español (LA)
499
+ "es-419": {
500
+ title: "Escanea para iniciar sesi\xF3n",
501
+ titleApprove: "Aprueba desde tu celular",
502
+ bodyScan: "Escanea con la c\xE1mara de tu celular o con la app ZOREAL ID.",
503
+ bodyApprove: "Aprueba el inicio de sesi\xF3n en tu app ZOREAL ID.",
504
+ bodyEnrolling: "Termina de configurar ZOREAL ID en tu celular y luego aprueba el inicio de sesi\xF3n.",
505
+ waiting: "Esperando escaneo",
506
+ waitingApproval: "Esperando aprobaci\xF3n",
507
+ expiresIn: "Expira en {time}",
508
+ secured: "Verificaci\xF3n Proof-of-Human de ZOREAL",
509
+ noIdTitle: "\xBFTodav\xEDa no tienes ZOREAL ID?",
510
+ noIdBody: "Escanea el mismo c\xF3digo para descargar la app y crear uno gratis. Solo toma un minuto.",
511
+ cancel: "Cancelar",
512
+ close: "Cerrar",
513
+ qrAlt: "C\xF3digo QR para iniciar sesi\xF3n con ZOREAL"
514
+ },
515
+ // Suomi
516
+ fi: {
517
+ title: "Kirjaudu sis\xE4\xE4n skannaamalla",
518
+ titleApprove: "Hyv\xE4ksy puhelimessasi",
519
+ bodyScan: "Skannaa puhelimesi kameralla tai ZOREAL ID -sovelluksella.",
520
+ bodyApprove: "Hyv\xE4ksy kirjautuminen ZOREAL ID -sovelluksessasi.",
521
+ bodyEnrolling: "Viimeistele ZOREAL ID -sovelluksen k\xE4ytt\xF6\xF6notto puhelimellasi ja hyv\xE4ksy sitten kirjautuminen.",
522
+ waiting: "Odotetaan skannausta",
523
+ waitingApproval: "Odotetaan hyv\xE4ksynt\xE4\xE4",
524
+ expiresIn: "Vanhenee {time} kuluttua",
525
+ secured: "ZOREALin Proof-of-Human-vahvistus",
526
+ noIdTitle: "Eik\xF6 sinulla ole viel\xE4 ZOREAL ID:t\xE4?",
527
+ noIdBody: "Skannaa sama koodi ladataksesi sovelluksen ja luodaksesi tunnuksen ilmaiseksi. Se vie vain minuutin.",
528
+ cancel: "Peruuta",
529
+ close: "Sulje",
530
+ qrAlt: "QR-koodi ZOREAL-kirjautumista varten"
531
+ },
532
+ // עברית
533
+ he: {
534
+ title: "\u05E1\u05E8\u05D5\u05E7 \u05DB\u05D3\u05D9 \u05DC\u05D4\u05EA\u05D7\u05D1\u05E8",
535
+ titleApprove: "\u05D0\u05E9\u05E8 \u05D1\u05D8\u05DC\u05E4\u05D5\u05DF \u05E9\u05DC\u05DA",
536
+ bodyScan: "\u05E1\u05E8\u05D5\u05E7 \u05D1\u05D0\u05DE\u05E6\u05E2\u05D5\u05EA \u05DE\u05E6\u05DC\u05DE\u05EA \u05D4\u05D8\u05DC\u05E4\u05D5\u05DF \u05E9\u05DC\u05DA \u05D0\u05D5 \u05D0\u05E4\u05DC\u05D9\u05E7\u05E6\u05D9\u05D9\u05EA ZOREAL ID.",
537
+ bodyApprove: "\u05D0\u05E9\u05E8 \u05D0\u05EA \u05D4\u05D4\u05EA\u05D7\u05D1\u05E8\u05D5\u05EA \u05D1\u05D0\u05E4\u05DC\u05D9\u05E7\u05E6\u05D9\u05D9\u05EA ZOREAL ID \u05E9\u05DC\u05DA.",
538
+ bodyEnrolling: "\u05E1\u05D9\u05D9\u05DD \u05DC\u05D4\u05D2\u05D3\u05D9\u05E8 \u05D0\u05EA ZOREAL ID \u05D1\u05D8\u05DC\u05E4\u05D5\u05DF \u05E9\u05DC\u05DA, \u05D5\u05D0\u05D6 \u05D0\u05E9\u05E8 \u05D0\u05EA \u05D4\u05D4\u05EA\u05D7\u05D1\u05E8\u05D5\u05EA.",
539
+ waiting: "\u05DE\u05DE\u05EA\u05D9\u05DF \u05DC\u05E1\u05E8\u05D9\u05E7\u05D4",
540
+ waitingApproval: "\u05DE\u05DE\u05EA\u05D9\u05DF \u05DC\u05D0\u05D9\u05E9\u05D5\u05E8",
541
+ expiresIn: "\u05D9\u05E4\u05D5\u05D2 \u05D1\u05E2\u05D5\u05D3 {time}",
542
+ secured: "\u05D0\u05D9\u05DE\u05D5\u05EA Proof-of-Human \u05DE\u05D1\u05D9\u05EA ZOREAL",
543
+ noIdTitle: "\u05E2\u05D3\u05D9\u05D9\u05DF \u05D0\u05D9\u05DF \u05DC\u05DA ZOREAL ID?",
544
+ noIdBody: "\u05E1\u05E8\u05D5\u05E7 \u05D0\u05EA \u05D0\u05D5\u05EA\u05D5 \u05D4\u05E7\u05D5\u05D3 \u05DB\u05D3\u05D9 \u05DC\u05D4\u05D5\u05E8\u05D9\u05D3 \u05D0\u05EA \u05D4\u05D0\u05E4\u05DC\u05D9\u05E7\u05E6\u05D9\u05D4 \u05D5\u05DC\u05D9\u05E6\u05D5\u05E8 \u05D0\u05D7\u05D3 \u05D1\u05D7\u05D9\u05E0\u05DD. \u05D6\u05D4 \u05DC\u05D5\u05E7\u05D7 \u05E8\u05E7 \u05D3\u05E7\u05D4.",
545
+ cancel: "\u05D1\u05D9\u05D8\u05D5\u05DC",
546
+ close: "\u05E1\u05D2\u05D5\u05E8",
547
+ qrAlt: "\u05E7\u05D5\u05D3 QR \u05DC\u05D4\u05EA\u05D7\u05D1\u05E8\u05D5\u05EA \u05E2\u05DD ZOREAL"
548
+ },
549
+ // Hrvatski
550
+ hr: {
551
+ title: "Skenirajte za prijavu",
552
+ titleApprove: "Odobrite na svom mobitelu",
553
+ bodyScan: "Skenirajte kamerom svog mobitela ili aplikacijom ZOREAL ID.",
554
+ bodyApprove: "Odobrite prijavu u aplikaciji ZOREAL ID.",
555
+ bodyEnrolling: "Dovr\u0161ite postavljanje ZOREAL ID-a na svom mobitelu, a zatim odobrite prijavu.",
556
+ waiting: "\u010Ceka se skeniranje",
557
+ waitingApproval: "\u010Ceka se odobrenje",
558
+ expiresIn: "Isti\u010De za {time}",
559
+ secured: "ZOREAL Proof-of-Human provjera",
560
+ noIdTitle: "Nemate ZOREAL ID?",
561
+ noIdBody: "Skenirajte isti kod da preuzmete aplikaciju i besplatno ga izradite. Traje samo minutu.",
562
+ cancel: "Odustani",
563
+ close: "Zatvori",
564
+ qrAlt: "QR kod za prijavu putem ZOREAL-a"
565
+ },
566
+ // Magyar
567
+ hu: {
568
+ title: "Bejelentkez\xE9s beolvas\xE1ssal",
569
+ titleApprove: "J\xF3v\xE1hagy\xE1s a telefonj\xE1n",
570
+ bodyScan: "Olvassa be a telefonja kamer\xE1j\xE1val, vagy a ZOREAL ID alkalmaz\xE1ssal.",
571
+ bodyApprove: "Hagyja j\xF3v\xE1 a bejelentkez\xE9st a ZOREAL ID alkalmaz\xE1sban.",
572
+ bodyEnrolling: "Fejezze be a ZOREAL ID be\xE1ll\xEDt\xE1s\xE1t a telefonj\xE1n, majd hagyja j\xF3v\xE1 a bejelentkez\xE9st.",
573
+ waiting: "V\xE1rakoz\xE1s beolvas\xE1sra",
574
+ waitingApproval: "V\xE1rakoz\xE1s j\xF3v\xE1hagy\xE1sra",
575
+ expiresIn: "Lej\xE1r {time} m\xFAlva",
576
+ secured: "Proof-of-Human hiteles\xEDt\xE9s a ZOREAL-t\xF3l",
577
+ noIdTitle: "M\xE9g nincs ZOREAL ID-je?",
578
+ noIdBody: "Olvassa be ugyanazt a k\xF3dot az alkalmaz\xE1s let\xF6lt\xE9s\xE9hez, \xE9s hozzon l\xE9tre egyet ingyenesen. Mind\xF6ssze egy percet vesz ig\xE9nybe.",
579
+ cancel: "M\xE9gse",
580
+ close: "Bez\xE1r\xE1s",
581
+ qrAlt: "QR-k\xF3d a ZOREAL-lal val\xF3 bejelentkez\xE9shez"
582
+ },
583
+ // Bahasa Indonesia
584
+ id: {
585
+ title: "Pindai untuk masuk",
586
+ titleApprove: "Setujui di ponsel Anda",
587
+ bodyScan: "Pindai dengan kamera ponsel atau aplikasi ZOREAL ID.",
588
+ bodyApprove: "Setujui proses masuk di aplikasi ZOREAL ID Anda.",
589
+ bodyEnrolling: "Selesaikan pengaturan ZOREAL ID di ponsel Anda, lalu setujui proses masuk.",
590
+ waiting: "Menunggu pemindaian",
591
+ waitingApproval: "Menunggu persetujuan",
592
+ expiresIn: "Berakhir dalam {time}",
593
+ secured: "Verifikasi Proof-of-Human oleh ZOREAL",
594
+ noIdTitle: "Belum punya ZOREAL ID?",
595
+ noIdBody: "Pindai kode yang sama untuk mengunduh aplikasi dan membuat akun secara gratis. Hanya butuh waktu satu menit.",
596
+ cancel: "Batal",
597
+ close: "Tutup",
598
+ qrAlt: "Kode QR untuk masuk dengan ZOREAL"
599
+ },
600
+ // Italiano
601
+ it: {
602
+ title: "Scansiona per accedere",
603
+ titleApprove: "Approva sul tuo telefono",
604
+ bodyScan: "Scansiona con la fotocamera del telefono o con l'app ZOREAL ID.",
605
+ bodyApprove: "Approva l'accesso nell'app ZOREAL ID.",
606
+ bodyEnrolling: "Completa la configurazione di ZOREAL ID sul telefono, poi approva l'accesso.",
607
+ waiting: "In attesa della scansione",
608
+ waitingApproval: "In attesa di approvazione",
609
+ expiresIn: "Scade tra {time}",
610
+ secured: "Verifica Proof-of-Human di ZOREAL",
611
+ noIdTitle: "Non hai ancora uno ZOREAL ID?",
612
+ noIdBody: "Scansiona lo stesso codice per scaricare l'app e crearne uno gratis. Basta un minuto.",
613
+ cancel: "Annulla",
614
+ close: "Chiudi",
615
+ qrAlt: "Codice QR per accedere con ZOREAL"
616
+ },
617
+ // Bahasa Melayu
618
+ ms: {
619
+ title: "Imbas untuk log masuk",
620
+ titleApprove: "Luluskan di telefon anda",
621
+ bodyScan: "Imbas dengan kamera telefon atau aplikasi ZOREAL ID.",
622
+ bodyApprove: "Luluskan log masuk dalam aplikasi ZOREAL ID anda.",
623
+ bodyEnrolling: "Selesaikan persediaan ZOREAL ID di telefon anda, kemudian luluskan log masuk.",
624
+ waiting: "Menunggu imbasan",
625
+ waitingApproval: "Menunggu kelulusan",
626
+ expiresIn: "Tamat tempoh dalam {time}",
627
+ secured: "Pengesahan Proof-of-Human oleh ZOREAL",
628
+ noIdTitle: "Belum ada ZOREAL ID?",
629
+ noIdBody: "Imbas kod yang sama untuk memuat turun aplikasi dan cipta satu secara percuma. Hanya mengambil masa seminit.",
630
+ cancel: "Batal",
631
+ close: "Tutup",
632
+ qrAlt: "Kod QR untuk log masuk dengan ZOREAL"
633
+ },
634
+ // Nederlands
635
+ nl: {
636
+ title: "Scan om in te loggen",
637
+ titleApprove: "Keur goed op je telefoon",
638
+ bodyScan: "Scan met de camera van je telefoon of de ZOREAL ID-app.",
639
+ bodyApprove: "Keur de aanmelding goed in je ZOREAL ID-app.",
640
+ bodyEnrolling: "Rond het instellen van ZOREAL ID op je telefoon af en keur daarna de aanmelding goed.",
641
+ waiting: "Wachten op scan",
642
+ waitingApproval: "Wachten op goedkeuring",
643
+ expiresIn: "Verloopt over {time}",
644
+ secured: "Proof-of-Human-verificatie door ZOREAL",
645
+ noIdTitle: "Nog geen ZOREAL ID?",
646
+ noIdBody: "Scan dezelfde code om de app te downloaden en gratis een account aan te maken. Dit duurt maar een minuut.",
647
+ cancel: "Annuleren",
648
+ close: "Sluiten",
649
+ qrAlt: "QR-code om in te loggen met ZOREAL"
650
+ },
651
+ // Norsk
652
+ no: {
653
+ title: "Skann for \xE5 logge inn",
654
+ titleApprove: "Godkjenn p\xE5 telefonen din",
655
+ bodyScan: "Skann med telefonens kamera eller ZOREAL ID-appen.",
656
+ bodyApprove: "Godkjenn innloggingen i ZOREAL ID-appen din.",
657
+ bodyEnrolling: "Fullf\xF8r oppsettet av ZOREAL ID p\xE5 telefonen din, og godkjenn deretter innloggingen.",
658
+ waiting: "Venter p\xE5 skanning",
659
+ waitingApproval: "Venter p\xE5 godkjenning",
660
+ expiresIn: "Utl\xF8per om {time}",
661
+ secured: "Proof-of-Human-verifisering av ZOREAL",
662
+ noIdTitle: "Har du ikke ZOREAL ID enn\xE5?",
663
+ noIdBody: "Skann den samme koden for \xE5 laste ned appen og opprette en gratis. Det tar bare et minutt.",
664
+ cancel: "Avbryt",
665
+ close: "Lukk",
666
+ qrAlt: "QR-kode for \xE5 logge inn med ZOREAL"
667
+ },
668
+ // Polski
669
+ pl: {
670
+ title: "Zeskanuj, aby si\u0119 zalogowa\u0107",
671
+ titleApprove: "Zatwierd\u017A w telefonie",
672
+ bodyScan: "Zeskanuj aparatem telefonu lub aplikacj\u0105 ZOREAL ID.",
673
+ bodyApprove: "Zatwierd\u017A logowanie w aplikacji ZOREAL ID.",
674
+ bodyEnrolling: "Doko\u0144cz konfiguracj\u0119 ZOREAL ID w telefonie, a nast\u0119pnie zatwierd\u017A logowanie.",
675
+ waiting: "Czekanie na skan",
676
+ waitingApproval: "Czekanie na zatwierdzenie",
677
+ expiresIn: "Wygasa za {time}",
678
+ secured: "Weryfikacja Proof-of-Human od ZOREAL",
679
+ noIdTitle: "Nie masz jeszcze ZOREAL ID?",
680
+ noIdBody: "Zeskanuj ten sam kod, aby pobra\u0107 aplikacj\u0119 i bezp\u0142atnie utworzy\u0107 ZOREAL ID. Zajmie to tylko minut\u0119.",
681
+ cancel: "Anuluj",
682
+ close: "Zamknij",
683
+ qrAlt: "Kod QR do logowania za pomoc\u0105 ZOREAL"
684
+ },
685
+ // Português (BR)
686
+ "pt-br": {
687
+ title: "Escaneie para entrar",
688
+ titleApprove: "Aprove no seu celular",
689
+ bodyScan: "Escaneie com a c\xE2mera do seu celular ou com o app ZOREAL ID.",
690
+ bodyApprove: "Aprove o login no app ZOREAL ID.",
691
+ bodyEnrolling: "Termine de configurar o ZOREAL ID no seu celular e depois aprove o login.",
692
+ waiting: "Aguardando escaneamento",
693
+ waitingApproval: "Aguardando aprova\xE7\xE3o",
694
+ expiresIn: "Expira em {time}",
695
+ secured: "Verifica\xE7\xE3o Proof-of-Human da ZOREAL",
696
+ noIdTitle: "Ainda n\xE3o tem um ZOREAL ID?",
697
+ noIdBody: "Escaneie o mesmo c\xF3digo para baixar o app e criar um de gra\xE7a. Leva s\xF3 um minuto.",
698
+ cancel: "Cancelar",
699
+ close: "Fechar",
700
+ qrAlt: "C\xF3digo QR para entrar com ZOREAL"
701
+ },
702
+ // Română
703
+ ro: {
704
+ title: "Scana\u021Bi pentru conectare",
705
+ titleApprove: "Aproba\u021Bi de pe telefon",
706
+ bodyScan: "Scana\u021Bi cu camera telefonului sau cu aplica\u021Bia ZOREAL ID.",
707
+ bodyApprove: "Aproba\u021Bi conectarea \xEEn aplica\u021Bia ZOREAL ID.",
708
+ bodyEnrolling: "Finaliza\u021Bi configurarea ZOREAL ID pe telefon, apoi aproba\u021Bi conectarea.",
709
+ waiting: "Se a\u0219teapt\u0103 scanarea",
710
+ waitingApproval: "Se a\u0219teapt\u0103 aprobarea",
711
+ expiresIn: "Expir\u0103 \xEEn {time}",
712
+ secured: "Verificare Proof-of-Human de la ZOREAL",
713
+ noIdTitle: "Nu ave\u021Bi \xEEnc\u0103 un ZOREAL ID?",
714
+ noIdBody: "Scana\u021Bi acela\u0219i cod pentru a desc\u0103rca aplica\u021Bia \u0219i a crea unul gratuit. Dureaz\u0103 doar un minut.",
715
+ cancel: "Anuleaz\u0103",
716
+ close: "\xCEnchide",
717
+ qrAlt: "Cod QR pentru conectare cu ZOREAL"
718
+ },
719
+ // Српски
720
+ sr: {
721
+ title: "\u0421\u043A\u0435\u043D\u0438\u0440\u0430\u0458\u0442\u0435 \u0437\u0430 \u043F\u0440\u0438\u0458\u0430\u0432\u0443",
722
+ titleApprove: "\u041E\u0434\u043E\u0431\u0440\u0438\u0442\u0435 \u043D\u0430 \u0441\u0432\u043E\u043C \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0443",
723
+ bodyScan: "\u0421\u043A\u0435\u043D\u0438\u0440\u0430\u0458\u0442\u0435 \u043A\u0430\u043C\u0435\u0440\u043E\u043C \u0441\u0432\u043E\u0433 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430 \u0438\u043B\u0438 \u0430\u043F\u043B\u0438\u043A\u0430\u0446\u0438\u0458\u043E\u043C ZOREAL ID.",
724
+ bodyApprove: "\u041E\u0434\u043E\u0431\u0440\u0438\u0442\u0435 \u043F\u0440\u0438\u0458\u0430\u0432\u0443 \u0443 \u0430\u043F\u043B\u0438\u043A\u0430\u0446\u0438\u0458\u0438 ZOREAL ID.",
725
+ bodyEnrolling: "\u0414\u043E\u0432\u0440\u0448\u0438\u0442\u0435 \u043F\u043E\u0434\u0435\u0448\u0430\u0432\u0430\u045A\u0435 ZOREAL ID-\u0430 \u043D\u0430 \u0441\u0432\u043E\u043C \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0443, \u043F\u0430 \u043E\u0434\u043E\u0431\u0440\u0438\u0442\u0435 \u043F\u0440\u0438\u0458\u0430\u0432\u0443.",
726
+ waiting: "\u0427\u0435\u043A\u0430 \u0441\u0435 \u0441\u043A\u0435\u043D\u0438\u0440\u0430\u045A\u0435",
727
+ waitingApproval: "\u0427\u0435\u043A\u0430 \u0441\u0435 \u043E\u0434\u043E\u0431\u0440\u0435\u045A\u0435",
728
+ expiresIn: "\u0418\u0441\u0442\u0438\u0447\u0435 \u0437\u0430 {time}",
729
+ secured: "ZOREAL Proof-of-Human \u0432\u0435\u0440\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0458\u0430",
730
+ noIdTitle: "\u041D\u0435\u043C\u0430\u0442\u0435 ZOREAL ID?",
731
+ noIdBody: "\u0421\u043A\u0435\u043D\u0438\u0440\u0430\u0458\u0442\u0435 \u0438\u0441\u0442\u0438 \u043A\u043E\u0434 \u0434\u0430 \u043F\u0440\u0435\u0443\u0437\u043C\u0435\u0442\u0435 \u0430\u043F\u043B\u0438\u043A\u0430\u0446\u0438\u0458\u0443 \u0438 \u0431\u0435\u0441\u043F\u043B\u0430\u0442\u043D\u043E \u0433\u0430 \u043D\u0430\u043F\u0440\u0430\u0432\u0438\u0442\u0435. \u0422\u0440\u0430\u0458\u0435 \u0441\u0430\u043C\u043E \u043C\u0438\u043D\u0443\u0442.",
732
+ cancel: "\u041E\u0442\u043A\u0430\u0436\u0438",
733
+ close: "\u0417\u0430\u0442\u0432\u043E\u0440\u0438",
734
+ qrAlt: "QR \u043A\u043E\u0434 \u0437\u0430 \u043F\u0440\u0438\u0458\u0430\u0432\u0443 \u043F\u0440\u0435\u043A\u043E ZOREAL-\u0430"
735
+ },
736
+ // ไทย
737
+ th: {
738
+ title: "\u0E2A\u0E41\u0E01\u0E19\u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A",
739
+ titleApprove: "\u0E2D\u0E19\u0E38\u0E21\u0E31\u0E15\u0E34\u0E1A\u0E19\u0E42\u0E17\u0E23\u0E28\u0E31\u0E1E\u0E17\u0E4C\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13",
740
+ bodyScan: "\u0E2A\u0E41\u0E01\u0E19\u0E14\u0E49\u0E27\u0E22\u0E01\u0E25\u0E49\u0E2D\u0E07\u0E42\u0E17\u0E23\u0E28\u0E31\u0E1E\u0E17\u0E4C\u0E2B\u0E23\u0E37\u0E2D\u0E41\u0E2D\u0E1B ZOREAL ID",
741
+ bodyApprove: "\u0E2D\u0E19\u0E38\u0E21\u0E31\u0E15\u0E34\u0E01\u0E32\u0E23\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u0E43\u0E19\u0E41\u0E2D\u0E1B ZOREAL ID \u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13",
742
+ bodyEnrolling: "\u0E15\u0E31\u0E49\u0E07\u0E04\u0E48\u0E32 ZOREAL ID \u0E1A\u0E19\u0E42\u0E17\u0E23\u0E28\u0E31\u0E1E\u0E17\u0E4C\u0E02\u0E2D\u0E07\u0E04\u0E38\u0E13\u0E43\u0E2B\u0E49\u0E40\u0E2A\u0E23\u0E47\u0E08\u0E2A\u0E34\u0E49\u0E19 \u0E41\u0E25\u0E49\u0E27\u0E2D\u0E19\u0E38\u0E21\u0E31\u0E15\u0E34\u0E01\u0E32\u0E23\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A",
743
+ waiting: "\u0E23\u0E2D\u0E01\u0E32\u0E23\u0E2A\u0E41\u0E01\u0E19",
744
+ waitingApproval: "\u0E23\u0E2D\u0E01\u0E32\u0E23\u0E2D\u0E19\u0E38\u0E21\u0E31\u0E15\u0E34",
745
+ expiresIn: "\u0E2B\u0E21\u0E14\u0E2D\u0E32\u0E22\u0E38\u0E43\u0E19 {time}",
746
+ secured: "\u0E01\u0E32\u0E23\u0E22\u0E37\u0E19\u0E22\u0E31\u0E19\u0E15\u0E31\u0E27\u0E15\u0E19 Proof-of-Human \u0E42\u0E14\u0E22 ZOREAL",
747
+ noIdTitle: "\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E21\u0E35 ZOREAL ID \u0E43\u0E0A\u0E48\u0E44\u0E2B\u0E21",
748
+ noIdBody: "\u0E2A\u0E41\u0E01\u0E19\u0E42\u0E04\u0E49\u0E14\u0E40\u0E14\u0E35\u0E22\u0E27\u0E01\u0E31\u0E19\u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E14\u0E32\u0E27\u0E19\u0E4C\u0E42\u0E2B\u0E25\u0E14\u0E41\u0E2D\u0E1B\u0E41\u0E25\u0E30\u0E2A\u0E23\u0E49\u0E32\u0E07\u0E1A\u0E31\u0E0D\u0E0A\u0E35\u0E1F\u0E23\u0E35 \u0E43\u0E0A\u0E49\u0E40\u0E27\u0E25\u0E32\u0E40\u0E1E\u0E35\u0E22\u0E07\u0E19\u0E32\u0E17\u0E35\u0E40\u0E14\u0E35\u0E22\u0E27",
749
+ cancel: "\u0E22\u0E01\u0E40\u0E25\u0E34\u0E01",
750
+ close: "\u0E1B\u0E34\u0E14",
751
+ qrAlt: "\u0E04\u0E34\u0E27\u0E2D\u0E32\u0E23\u0E4C\u0E42\u0E04\u0E49\u0E14\u0E2A\u0E33\u0E2B\u0E23\u0E31\u0E1A\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u0E14\u0E49\u0E27\u0E22 ZOREAL"
752
+ },
753
+ // Tagalog
754
+ tl: {
755
+ title: "I-scan para mag-sign in",
756
+ titleApprove: "I-approve sa iyong telepono",
757
+ bodyScan: "I-scan gamit ang camera ng iyong telepono o ang ZOREAL ID app.",
758
+ bodyApprove: "I-approve ang login sa iyong ZOREAL ID app.",
759
+ bodyEnrolling: "Tapusin muna ang pag-set up ng ZOREAL ID sa iyong telepono, pagkatapos ay i-approve ang login.",
760
+ waiting: "Naghihintay ng scan",
761
+ waitingApproval: "Naghihintay ng approval",
762
+ expiresIn: "Mag-e-expire sa {time}",
763
+ secured: "Proof-of-Human verification mula sa ZOREAL",
764
+ noIdTitle: "Wala ka pang ZOREAL ID?",
765
+ noIdBody: "I-scan ang parehong code para i-download ang app at gumawa ng iyong ZOREAL ID nang libre. Isang minuto lang ito.",
766
+ cancel: "Kanselahin",
767
+ close: "Isara",
768
+ qrAlt: "QR code para mag-sign in gamit ang ZOREAL"
769
+ },
770
+ // Türkçe
771
+ tr: {
772
+ title: "Giri\u015F i\xE7in taray\u0131n",
773
+ titleApprove: "Telefonunuzdan onaylay\u0131n",
774
+ bodyScan: "Telefonunuzun kameras\u0131yla veya ZOREAL ID uygulamas\u0131yla taray\u0131n.",
775
+ bodyApprove: "Giri\u015Fi ZOREAL ID uygulaman\u0131zdan onaylay\u0131n.",
776
+ bodyEnrolling: "Telefonunuzda ZOREAL ID kurulumunu tamamlay\u0131n, ard\u0131ndan giri\u015Fi onaylay\u0131n.",
777
+ waiting: "Tarama bekleniyor",
778
+ waitingApproval: "Onay bekleniyor",
779
+ expiresIn: "{time} i\xE7inde sona erer",
780
+ secured: "ZOREAL taraf\u0131ndan Proof-of-Human do\u011Frulamas\u0131",
781
+ noIdTitle: "Hen\xFCz ZOREAL ID'niz yok mu?",
782
+ noIdBody: "Uygulamay\u0131 indirmek ve \xFCcretsiz bir tane olu\u015Fturmak i\xE7in ayn\u0131 kodu taray\u0131n. Sadece bir dakikan\u0131z\u0131 al\u0131r.",
783
+ cancel: "\u0130ptal",
784
+ close: "Kapat",
785
+ qrAlt: "ZOREAL ile giri\u015F yapmak i\xE7in QR kodu"
786
+ },
787
+ // Українська
788
+ uk: {
789
+ title: "\u0421\u043A\u0430\u043D\u0443\u0439\u0442\u0435 \u0434\u043B\u044F \u0432\u0445\u043E\u0434\u0443",
790
+ titleApprove: "\u041F\u0456\u0434\u0442\u0432\u0435\u0440\u0434\u044C\u0442\u0435 \u043D\u0430 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0456",
791
+ bodyScan: "\u0421\u043A\u0430\u043D\u0443\u0439\u0442\u0435 \u043A\u0430\u043C\u0435\u0440\u043E\u044E \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0443 \u0430\u0431\u043E \u0434\u043E\u0434\u0430\u0442\u043A\u043E\u043C ZOREAL ID.",
792
+ bodyApprove: "\u041F\u0456\u0434\u0442\u0432\u0435\u0440\u0434\u044C\u0442\u0435 \u0432\u0445\u0456\u0434 \u0443 \u0434\u043E\u0434\u0430\u0442\u043A\u0443 ZOREAL ID.",
793
+ bodyEnrolling: "\u0417\u0430\u0432\u0435\u0440\u0448\u0456\u0442\u044C \u043D\u0430\u043B\u0430\u0448\u0442\u0443\u0432\u0430\u043D\u043D\u044F ZOREAL ID \u043D\u0430 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0456, \u0430 \u043F\u043E\u0442\u0456\u043C \u043F\u0456\u0434\u0442\u0432\u0435\u0440\u0434\u044C\u0442\u0435 \u0432\u0445\u0456\u0434.",
794
+ waiting: "\u041E\u0447\u0456\u043A\u0443\u0432\u0430\u043D\u043D\u044F \u0441\u043A\u0430\u043D\u0443\u0432\u0430\u043D\u043D\u044F",
795
+ waitingApproval: "\u041E\u0447\u0456\u043A\u0443\u0432\u0430\u043D\u043D\u044F \u043F\u0456\u0434\u0442\u0432\u0435\u0440\u0434\u0436\u0435\u043D\u043D\u044F",
796
+ expiresIn: "\u0421\u043F\u043B\u0438\u0432\u0430\u0454 \u0447\u0435\u0440\u0435\u0437 {time}",
797
+ secured: "\u041F\u0435\u0440\u0435\u0432\u0456\u0440\u043A\u0430 Proof-of-Human \u0432\u0456\u0434 ZOREAL",
798
+ noIdTitle: "\u0429\u0435 \u043D\u0435\u043C\u0430\u0454 ZOREAL ID?",
799
+ noIdBody: "\u0421\u043A\u0430\u043D\u0443\u0439\u0442\u0435 \u0442\u043E\u0439 \u0441\u0430\u043C\u0438\u0439 \u043A\u043E\u0434, \u0449\u043E\u0431 \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0434\u043E\u0434\u0430\u0442\u043E\u043A \u0456 \u0431\u0435\u0437\u043A\u043E\u0448\u0442\u043E\u0432\u043D\u043E \u0441\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u0439\u043E\u0433\u043E. \u0426\u0435 \u0437\u0430\u0439\u043C\u0435 \u043B\u0438\u0448\u0435 \u0445\u0432\u0438\u043B\u0438\u043D\u0443.",
800
+ cancel: "\u0421\u043A\u0430\u0441\u0443\u0432\u0430\u0442\u0438",
801
+ close: "\u0417\u0430\u043A\u0440\u0438\u0442\u0438",
802
+ qrAlt: "QR-\u043A\u043E\u0434 \u0434\u043B\u044F \u0432\u0445\u043E\u0434\u0443 \u0447\u0435\u0440\u0435\u0437 ZOREAL"
803
+ },
804
+ // اردو
805
+ ur: {
806
+ title: "\u0644\u0627\u06AF \u0627\u0650\u0646 \u06A9\u0631\u0646\u06D2 \u06A9\u06D2 \u0644\u06CC\u06D2 \u0627\u0633\u06A9\u06CC\u0646 \u06A9\u0631\u06CC\u06BA",
807
+ titleApprove: "\u0627\u067E\u0646\u06D2 \u0641\u0648\u0646 \u067E\u0631 \u0645\u0646\u0638\u0648\u0631\u06CC \u062F\u06CC\u06BA",
808
+ bodyScan: "\u0627\u067E\u0646\u06D2 \u0641\u0648\u0646 \u06A9\u06D2 \u06A9\u06CC\u0645\u0631\u06D2 \u06CC\u0627 ZOREAL ID \u0627\u06CC\u067E \u0633\u06D2 \u0627\u0633\u06A9\u06CC\u0646 \u06A9\u0631\u06CC\u06BA\u06D4",
809
+ bodyApprove: "\u0627\u067E\u0646\u06CC ZOREAL ID \u0627\u06CC\u067E \u0645\u06CC\u06BA \u0644\u0627\u06AF \u0627\u0650\u0646 \u06A9\u06CC \u0645\u0646\u0638\u0648\u0631\u06CC \u062F\u06CC\u06BA\u06D4",
810
+ bodyEnrolling: "\u0627\u067E\u0646\u06D2 \u0641\u0648\u0646 \u067E\u0631 ZOREAL ID \u06A9\u06CC \u0633\u06CC\u0679 \u0627\u067E \u0645\u06A9\u0645\u0644 \u06A9\u0631\u06CC\u06BA\u060C \u067E\u06BE\u0631 \u0644\u0627\u06AF \u0627\u0650\u0646 \u06A9\u06CC \u0645\u0646\u0638\u0648\u0631\u06CC \u062F\u06CC\u06BA\u06D4",
811
+ waiting: "\u0627\u0633\u06A9\u06CC\u0646 \u06A9\u0627 \u0627\u0646\u062A\u0638\u0627\u0631",
812
+ waitingApproval: "\u0645\u0646\u0638\u0648\u0631\u06CC \u06A9\u0627 \u0627\u0646\u062A\u0638\u0627\u0631",
813
+ expiresIn: "{time} \u0645\u06CC\u06BA \u062E\u062A\u0645 \u06C1\u0648\u06AF\u0627",
814
+ secured: "ZOREAL \u06A9\u06CC \u062C\u0627\u0646\u0628 \u0633\u06D2 Proof-of-Human \u062A\u0635\u062F\u06CC\u0642",
815
+ noIdTitle: "\u0627\u0628\u06BE\u06CC \u062A\u06A9 ZOREAL ID \u0646\u06C1\u06CC\u06BA \u06C1\u06D2\u061F",
816
+ noIdBody: "\u0627\u06CC\u067E \u0688\u0627\u0624\u0646 \u0644\u0648\u0688 \u06A9\u0631\u0646\u06D2 \u0627\u0648\u0631 \u0645\u0641\u062A \u0645\u06CC\u06BA \u0627\u06CC\u06A9 \u0628\u0646\u0627\u0646\u06D2 \u06A9\u06D2 \u0644\u06CC\u06D2 \u0648\u06C1\u06CC \u06A9\u0648\u0688 \u0627\u0633\u06A9\u06CC\u0646 \u06A9\u0631\u06CC\u06BA\u06D4 \u0627\u0633 \u0645\u06CC\u06BA \u0635\u0631\u0641 \u0627\u06CC\u06A9 \u0645\u0646\u0679 \u0644\u06AF\u062A\u0627 \u06C1\u06D2\u06D4",
817
+ cancel: "\u0645\u0646\u0633\u0648\u062E \u06A9\u0631\u06CC\u06BA",
818
+ close: "\u0628\u0646\u062F \u06A9\u0631\u06CC\u06BA",
819
+ qrAlt: "ZOREAL \u06A9\u06D2 \u0633\u0627\u062A\u06BE \u0644\u0627\u06AF \u0627\u0650\u0646 \u06A9\u0631\u0646\u06D2 \u06A9\u06D2 \u0644\u06CC\u06D2 QR \u06A9\u0648\u0688"
820
+ },
821
+ // Tiếng Việt
822
+ vi: {
823
+ title: "Qu\xE9t \u0111\u1EC3 \u0111\u0103ng nh\u1EADp",
824
+ titleApprove: "Ph\xEA duy\u1EC7t tr\xEAn \u0111i\u1EC7n tho\u1EA1i c\u1EE7a b\u1EA1n",
825
+ bodyScan: "Qu\xE9t b\u1EB1ng camera \u0111i\u1EC7n tho\u1EA1i ho\u1EB7c \u1EE9ng d\u1EE5ng ZOREAL ID.",
826
+ bodyApprove: "Ph\xEA duy\u1EC7t \u0111\u0103ng nh\u1EADp trong \u1EE9ng d\u1EE5ng ZOREAL ID c\u1EE7a b\u1EA1n.",
827
+ bodyEnrolling: "Ho\xE0n t\u1EA5t thi\u1EBFt l\u1EADp ZOREAL ID tr\xEAn \u0111i\u1EC7n tho\u1EA1i, sau \u0111\xF3 ph\xEA duy\u1EC7t \u0111\u0103ng nh\u1EADp.",
828
+ waiting: "\u0110ang ch\u1EDD qu\xE9t m\xE3",
829
+ waitingApproval: "\u0110ang ch\u1EDD ph\xEA duy\u1EC7t",
830
+ expiresIn: "H\u1EBFt h\u1EA1n sau {time}",
831
+ secured: "X\xE1c minh Proof-of-Human b\u1EDFi ZOREAL",
832
+ noIdTitle: "Ch\u01B0a c\xF3 ZOREAL ID?",
833
+ noIdBody: "Qu\xE9t c\xF9ng m\xE3 n\xE0y \u0111\u1EC3 t\u1EA3i \u1EE9ng d\u1EE5ng v\xE0 t\u1EA1o t\xE0i kho\u1EA3n mi\u1EC5n ph\xED. Ch\u1EC9 m\u1EA5t m\u1ED9t ph\xFAt.",
834
+ cancel: "H\u1EE7y",
835
+ close: "\u0110\xF3ng",
836
+ qrAlt: "M\xE3 QR \u0111\u1EC3 \u0111\u0103ng nh\u1EADp b\u1EB1ng ZOREAL"
837
+ }
838
+ };
839
+ var RTL = /* @__PURE__ */ new Set(["ar", "he", "iw", "ur"]);
840
+ var ALIASES = {
841
+ nb: "no",
842
+ // Bokmål — what we actually wrote
843
+ nn: "no",
844
+ // Nynorsk reader, served Bokmål: closer than English
845
+ fil: "tl",
846
+ // Filipino / Tagalog
847
+ iw: "he",
848
+ // superseded code for Hebrew, still emitted by some platforms
849
+ in: "id"
850
+ // superseded code for Indonesian
851
+ };
852
+ var LATAM = /* @__PURE__ */ new Set([
853
+ "ar",
854
+ "bo",
855
+ "cl",
856
+ "co",
857
+ "cr",
858
+ "cu",
859
+ "do",
860
+ "ec",
861
+ "gt",
862
+ "hn",
863
+ "mx",
864
+ "ni",
865
+ "pa",
866
+ "pe",
867
+ "pr",
868
+ "py",
869
+ "sv",
870
+ "uy",
871
+ "ve",
872
+ "419"
873
+ ]);
874
+ function lookup(locale) {
875
+ const tag = locale.toLowerCase().replace(/_/g, "-");
876
+ const parts = tag.split("-");
877
+ const primary = ALIASES[parts[0]] ?? parts[0];
878
+ const region = parts[1];
879
+ if (primary === "zh") {
880
+ const simplified = /(^|-)(hans|cn|sg|my)(-|$)/.test(tag);
881
+ return TRANSLATIONS[simplified ? "zhs" : "zht"];
882
+ }
883
+ if (primary === "es" && region && LATAM.has(region)) return TRANSLATIONS["es-419"];
884
+ if (primary === "pt" && region === "br") return TRANSLATIONS["pt-br"];
885
+ return TRANSLATIONS[tag] ?? TRANSLATIONS[primary];
886
+ }
887
+ function browserLocales() {
888
+ if (typeof navigator === "undefined") return [];
889
+ const nav = navigator;
890
+ if (nav.languages && nav.languages.length) return [...nav.languages];
891
+ return nav.language ? [nav.language] : [];
892
+ }
893
+ function strings(locale) {
894
+ if (locale) return lookup(locale) ?? en;
895
+ for (const candidate of browserLocales()) {
896
+ const hit = lookup(candidate);
897
+ if (hit) return hit;
898
+ }
899
+ return en;
900
+ }
901
+ function isRtl(locale) {
902
+ const tag = locale ?? browserLocales()[0];
903
+ if (!tag) return false;
904
+ return RTL.has(tag.toLowerCase().replace(/_/g, "-").split("-")[0]);
905
+ }
906
+ function interpolate(template, time) {
907
+ return template.replace("{time}", time);
908
+ }
909
+
910
+ // src/styles.ts
911
+ var PREFIX = "zrl";
912
+ var cx = (name) => `${PREFIX}-${name}`;
913
+ var STYLE_ELEMENT_ID = "zoreal-pairing-styles";
914
+ var LIGHT = `
915
+ --zrl-scrim: rgba(16, 18, 27, 0.45);
916
+ --zrl-surface: #ffffff;
917
+ --zrl-surface-sunken: #f6f7f9;
918
+ --zrl-ink: #16181c;
919
+ --zrl-ink-soft: #4a4f57;
920
+ --zrl-ink-mute: #6b7078;
921
+ --zrl-line: #e4e6ea;
922
+ --zrl-line-soft: #eef0f3;
923
+ --zrl-accent: #00b4d9;
924
+ --zrl-accent-soft: #dcf3fa;
925
+ --zrl-accent-ink: #04698a;
926
+ --zrl-urgent: #b4761a;
927
+ --zrl-qr-bg: #ffffff;
928
+ --zrl-shadow: 0 1px 2px rgba(16, 18, 27, 0.06), 0 20px 50px -12px rgba(16, 18, 27, 0.3);
929
+ --zrl-ring: rgba(16, 18, 27, 0.07);
930
+ `;
931
+ var DARK = `
932
+ --zrl-scrim: rgba(0, 0, 0, 0.62);
933
+ --zrl-surface: #17191d;
934
+ --zrl-surface-sunken: #1f2226;
935
+ --zrl-ink: #f4f5f7;
936
+ --zrl-ink-soft: #b3b8c0;
937
+ --zrl-ink-mute: #8b9199;
938
+ --zrl-line: #2c3036;
939
+ --zrl-line-soft: #24272c;
940
+ --zrl-accent: #34c9e8;
941
+ --zrl-accent-soft: #0d3b47;
942
+ --zrl-accent-ink: #7fdcf0;
943
+ --zrl-urgent: #e0a952;
944
+ /* The QR well stays white in dark mode on purpose: a scanner needs the
945
+ quiet-zone contrast, and an inverted QR fails on a good number of phone
946
+ cameras. It reads as a deliberate light panel, not a theming miss. */
947
+ --zrl-qr-bg: #ffffff;
948
+ --zrl-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 20px 50px -12px rgba(0, 0, 0, 0.65);
949
+ --zrl-ring: rgba(255, 255, 255, 0.1);
950
+ `;
951
+ var CSS = `
952
+ .${PREFIX}-root { ${LIGHT} }
953
+ .${PREFIX}-root[data-theme="dark"] { ${DARK} }
954
+ @media (prefers-color-scheme: dark) {
955
+ .${PREFIX}-root[data-theme="auto"] { ${DARK} }
956
+ }
957
+
958
+ .${PREFIX}-scrim {
959
+ position: fixed;
960
+ inset: 0;
961
+ z-index: 2147483000;
962
+ display: grid;
963
+ place-items: center;
964
+ overflow-y: auto;
965
+ padding: 16px;
966
+ background: var(--zrl-scrim);
967
+ backdrop-filter: blur(3px);
968
+ -webkit-backdrop-filter: blur(3px);
969
+ font-family: inherit;
970
+ animation: ${PREFIX}-fade 200ms ease-out both;
971
+ }
972
+
973
+ .${PREFIX}-card {
974
+ position: relative;
975
+ box-sizing: border-box;
976
+ width: 100%;
977
+ max-width: 380px;
978
+ border-radius: 16px;
979
+ background: var(--zrl-surface);
980
+ color: var(--zrl-ink);
981
+ box-shadow: var(--zrl-shadow);
982
+ outline: 1px solid var(--zrl-ring);
983
+ outline-offset: -1px;
984
+ text-align: center;
985
+ animation: ${PREFIX}-rise 300ms cubic-bezier(0.23, 1, 0.32, 1) both;
986
+ }
987
+
988
+ .${PREFIX}-body { padding: 28px 24px 20px; }
989
+
990
+ .${PREFIX}-lockup { display: block; margin: 0 auto; color: var(--zrl-ink); }
991
+
992
+ .${PREFIX}-title {
993
+ margin: 18px 0 0;
994
+ font-size: 18px;
995
+ font-weight: 600;
996
+ letter-spacing: -0.01em;
997
+ line-height: 1.3;
998
+ color: var(--zrl-ink);
999
+ }
1000
+
1001
+ .${PREFIX}-body-text {
1002
+ margin: 6px auto 0;
1003
+ max-width: 30ch;
1004
+ font-size: 14px;
1005
+ line-height: 1.55;
1006
+ color: var(--zrl-ink-soft);
1007
+ }
1008
+
1009
+ .${PREFIX}-qr-well {
1010
+ position: relative;
1011
+ display: grid;
1012
+ place-items: center;
1013
+ box-sizing: border-box;
1014
+ width: 204px;
1015
+ height: 204px;
1016
+ margin: 20px auto 0;
1017
+ padding: 12px;
1018
+ border: 1px solid var(--zrl-line);
1019
+ border-radius: 16px;
1020
+ background: var(--zrl-qr-bg);
1021
+ }
1022
+
1023
+ .${PREFIX}-qr {
1024
+ display: block;
1025
+ width: 100%;
1026
+ height: 100%;
1027
+ border-radius: 8px;
1028
+ transition: filter 300ms cubic-bezier(0.23, 1, 0.32, 1),
1029
+ opacity 300ms cubic-bezier(0.23, 1, 0.32, 1),
1030
+ transform 300ms cubic-bezier(0.23, 1, 0.32, 1);
1031
+ }
1032
+
1033
+ /* Once the code is claimed the QR is spent. Blurring it out rather than
1034
+ swapping it keeps one object on screen through the state change, so the eye
1035
+ reads a transformation instead of two things trading places. */
1036
+ .${PREFIX}-qr[data-spent="true"] { opacity: 0.2; filter: blur(3px); transform: scale(0.96); }
1037
+
1038
+ .${PREFIX}-qr-overlay {
1039
+ position: absolute;
1040
+ inset: 0;
1041
+ display: grid;
1042
+ place-items: center;
1043
+ animation: ${PREFIX}-fade 200ms ease-out both;
1044
+ }
1045
+
1046
+ .${PREFIX}-qr-badge {
1047
+ display: grid;
1048
+ place-items: center;
1049
+ width: 56px;
1050
+ height: 56px;
1051
+ border-radius: 999px;
1052
+ background: var(--zrl-accent-soft);
1053
+ color: var(--zrl-accent-ink);
1054
+ }
1055
+
1056
+ .${PREFIX}-status {
1057
+ display: flex;
1058
+ align-items: center;
1059
+ justify-content: center;
1060
+ gap: 8px;
1061
+ margin-top: 20px;
1062
+ font-size: 14px;
1063
+ font-weight: 500;
1064
+ color: var(--zrl-ink);
1065
+ }
1066
+
1067
+ .${PREFIX}-dot { position: relative; display: grid; place-items: center; width: 8px; height: 8px; }
1068
+ .${PREFIX}-dot i {
1069
+ position: absolute;
1070
+ width: 8px;
1071
+ height: 8px;
1072
+ border-radius: 999px;
1073
+ background: var(--zrl-accent);
1074
+ font-style: normal;
1075
+ }
1076
+ .${PREFIX}-dot i:first-child { animation: ${PREFIX}-ping 1.8s cubic-bezier(0.23, 1, 0.32, 1) infinite; }
1077
+
1078
+ .${PREFIX}-timer {
1079
+ margin: 4px 0 0;
1080
+ font-size: 12px;
1081
+ font-variant-numeric: tabular-nums;
1082
+ color: var(--zrl-ink-mute);
1083
+ transition: color 200ms ease-out;
1084
+ }
1085
+ .${PREFIX}-timer[data-urgent="true"] { color: var(--zrl-urgent); }
1086
+
1087
+ .${PREFIX}-help {
1088
+ padding: 14px 24px;
1089
+ border-top: 1px solid var(--zrl-line-soft);
1090
+ background: var(--zrl-surface-sunken);
1091
+ border-radius: 0;
1092
+ }
1093
+ .${PREFIX}-help-title { margin: 0; font-size: 12px; font-weight: 600; color: var(--zrl-ink); }
1094
+ .${PREFIX}-help-body {
1095
+ margin: 4px auto 0;
1096
+ max-width: 34ch;
1097
+ font-size: 12px;
1098
+ line-height: 1.55;
1099
+ color: var(--zrl-ink-soft);
1100
+ }
1101
+
1102
+ .${PREFIX}-footer { padding: 12px; border-top: 1px solid var(--zrl-line-soft); }
1103
+
1104
+ .${PREFIX}-cancel {
1105
+ display: block;
1106
+ width: 100%;
1107
+ padding: 10px;
1108
+ border: 0;
1109
+ border-radius: 12px;
1110
+ background: transparent;
1111
+ font: inherit;
1112
+ font-size: 14px;
1113
+ font-weight: 500;
1114
+ color: var(--zrl-ink-soft);
1115
+ cursor: pointer;
1116
+ transition: background-color 150ms ease-out, color 150ms ease-out, transform 150ms ease-out;
1117
+ }
1118
+ .${PREFIX}-cancel:hover { background: var(--zrl-surface-sunken); color: var(--zrl-ink); }
1119
+ .${PREFIX}-cancel:active { transform: scale(0.99); }
1120
+
1121
+ .${PREFIX}-secured {
1122
+ display: flex;
1123
+ align-items: center;
1124
+ justify-content: center;
1125
+ gap: 6px;
1126
+ margin: 6px 0 0;
1127
+ font-size: 12px;
1128
+ color: var(--zrl-ink-mute);
1129
+ }
1130
+
1131
+ .${PREFIX}-close {
1132
+ position: absolute;
1133
+ top: 12px;
1134
+ inset-inline-end: 12px;
1135
+ display: grid;
1136
+ place-items: center;
1137
+ width: 32px;
1138
+ height: 32px;
1139
+ padding: 0;
1140
+ border: 0;
1141
+ border-radius: 8px;
1142
+ background: transparent;
1143
+ color: var(--zrl-ink-mute);
1144
+ cursor: pointer;
1145
+ transition: background-color 150ms ease-out, color 150ms ease-out, transform 150ms ease-out;
1146
+ }
1147
+ .${PREFIX}-close:hover { background: var(--zrl-surface-sunken); color: var(--zrl-ink); }
1148
+ .${PREFIX}-close:active { transform: scale(0.95); }
1149
+
1150
+ .${PREFIX}-card :focus-visible {
1151
+ outline: 2px solid var(--zrl-accent);
1152
+ outline-offset: 2px;
1153
+ }
1154
+
1155
+ @keyframes ${PREFIX}-fade { from { opacity: 0 } to { opacity: 1 } }
1156
+ @keyframes ${PREFIX}-rise {
1157
+ from { opacity: 0; transform: translateY(10px) scale(0.98) }
1158
+ to { opacity: 1; transform: none }
1159
+ }
1160
+ @keyframes ${PREFIX}-ping {
1161
+ 0% { transform: scale(1); opacity: 0.5 }
1162
+ 70%, 100% { transform: scale(2.6); opacity: 0 }
1163
+ }
1164
+
1165
+ @media (prefers-reduced-motion: reduce) {
1166
+ .${PREFIX}-scrim,
1167
+ .${PREFIX}-card,
1168
+ .${PREFIX}-qr-overlay { animation: none }
1169
+ .${PREFIX}-dot i:first-child { animation: none; opacity: 0.35 }
1170
+ .${PREFIX}-qr,
1171
+ .${PREFIX}-cancel,
1172
+ .${PREFIX}-close,
1173
+ .${PREFIX}-timer { transition: none }
1174
+ }
1175
+ `;
1176
+ function ensureStyles() {
1177
+ if (typeof document === "undefined") return;
1178
+ if (document.getElementById(STYLE_ELEMENT_ID)) return;
1179
+ const el2 = document.createElement("style");
1180
+ el2.id = STYLE_ELEMENT_ID;
1181
+ el2.textContent = CSS;
1182
+ document.head.appendChild(el2);
1183
+ }
1184
+
1185
+ // src/modal.ts
1186
+ var DEFAULT_PAIRING_TIMEOUT_MS = 12e4;
1187
+ var URGENT_SECONDS = 20;
1188
+ function mmss(totalSeconds) {
1189
+ const m = Math.floor(totalSeconds / 60);
1190
+ const s = totalSeconds % 60;
1191
+ return `${m}:${String(s).padStart(2, "0")}`;
1192
+ }
1193
+ function el(tag, className, text) {
1194
+ const node = document.createElement(tag);
1195
+ if (className) node.className = className;
1196
+ if (text !== void 0) node.textContent = text;
1197
+ return node;
1198
+ }
1199
+ var SVG_NS = "http://www.w3.org/2000/svg";
1200
+ function svg(viewBox, attrs = {}) {
1201
+ const node = document.createElementNS(SVG_NS, "svg");
1202
+ node.setAttribute("viewBox", viewBox);
1203
+ node.setAttribute("focusable", "false");
1204
+ node.setAttribute("aria-hidden", "true");
1205
+ for (const [k, v] of Object.entries(attrs)) node.setAttribute(k, v);
1206
+ return node;
1207
+ }
1208
+ function path(d, attrs = {}) {
1209
+ const node = document.createElementNS(SVG_NS, "path");
1210
+ node.setAttribute("d", d);
1211
+ for (const [k, v] of Object.entries(attrs)) node.setAttribute(k, v);
1212
+ return node;
1213
+ }
1214
+ function strokeIcon(size, ds, width = "2") {
1215
+ const node = svg("0 0 24 24", {
1216
+ width: String(size),
1217
+ height: String(size),
1218
+ fill: "none",
1219
+ stroke: "currentColor",
1220
+ "stroke-width": width,
1221
+ "stroke-linecap": "round",
1222
+ "stroke-linejoin": "round"
1223
+ });
1224
+ for (const d of ds) node.appendChild(path(d));
1225
+ return node;
1226
+ }
1227
+ var ZOREAL_BLUE = "#00b4d9";
1228
+ var WORDMARK = "M205,40.5h15.3v-3.5h-11.5v-18.4h-3.8v21.8ZM157,22.2v5.6h10.9v3.5h-10.9v5.8h12.5v3.5h-16.3v-21.8h16.2v3.5h-12.4ZM141.4,25.8c0,1.1-.4,2-1.2,2.7-.8.7-1.9,1-3.3,1h-5.6v-7.3h5.6c1.4,0,2.6.3,3.4.9.8.6,1.2,1.5,1.2,2.7ZM146,40.5l-5.9-8.3c.8-.2,1.4-.5,2.1-.9s1.2-.9,1.7-1.4c.4-.5.8-1.2,1.1-1.9s.4-1.5.4-2.4-.1-2-.5-2.9c-.4-.9-.9-1.6-1.7-2.2-.6-.6-1.5-1-2.5-1.4-1-.3-2.2-.4-3.4-.4h-9.8v21.8h3.8v-7.6h4.8l5.4,7.6h4.5ZM115.7,29.7c0,1.1-.1,2.1-.5,3s-.9,1.7-1.5,2.4-1.4,1.2-2.4,1.7c-.9.4-1.9.6-3,.6s-2.1-.1-3-.6-1.7-1-2.4-1.7-1.2-1.5-1.5-2.4-.5-1.9-.5-3,.1-2.1.5-3,.9-1.7,1.5-2.4,1.4-1.2,2.4-1.7c.9-.4,1.9-.6,3-.6s2.1.2,3,.6c.9.4,1.7,1,2.3,1.7.6.6,1.2,1.5,1.6,2.4s.5,1.9.5,3ZM119.7,29.6c0-1.5-.3-3-.8-4.4-.6-1.4-1.4-2.5-2.4-3.6-1-1-2.2-1.8-3.6-2.4-1.4-.6-3-.9-4.6-.9s-3.2.4-4.6.9c-1.4.6-2.7,1.4-3.7,2.4s-1.8,2.2-2.4,3.6c-.5,1.4-.8,2.8-.8,4.4s.3,3,.8,4.4c.6,1.4,1.4,2.5,2.4,3.6,1,1,2.2,1.8,3.6,2.4,1.4.6,3,.9,4.6.9s3.2-.4,4.6-.9c1.4-.6,2.6-1.4,3.7-2.4,1-1,1.8-2.2,2.4-3.6.5-1.4.8-2.9.8-4.4ZM86.1,22.1l-13,15.6v2.8h17.9v-3.4h-12.9l12.9-15.6v-2.8h-17.5v3.4h12.5ZM188.5,18.5h-3.5l-9.6,22h4c3.7-8.8,3.4-8,7.4-17.4,3.7,8.8,3.9,9.1,7.4,17.4h4l-9.6-22Z";
1229
+ var MARK_PATHS = [
1230
+ "M52,25.7c.4-2-.5-4.2-2.5-5.4l-11.8-6.8,3.4-2,10.1,5.9c3.6,2,5.1,6.3,3.8,10.1-.2.5-.4,1-.7,1.6-.3.5-.6.9-1,1.4-.9.9-1.9,1.7-3,2.2-2.4,1-5.2.9-7.6-.5l-5.9-3.4c-1.9-1.1-4.3-.9-5.9.5-.4.4-.8.8-1.1,1.3-.3.5-.5,1.1-.6,1.7-.4,2,.6,4.2,2.5,5.4l11.8,6.8-3.4,2-10.1-5.9c-3.6-2-5.1-6.3-3.8-10.1.1-.5.4-1,.7-1.6.3-.5.7-.9,1-1.4.9-.9,1.9-1.7,3.1-2.2,2.4-1,5.2-.9,7.6.4l5.9,3.4c1.9,1.1,4.3.9,5.9-.5.4-.4.8-.8,1.1-1.3.3-.5.5-1.1.6-1.7Z",
1231
+ "M60.3,33.1c-.5.8-1.5,1.1-2.3.6-.9-.5-1.1-1.5-.7-2.3.5-.9,1.5-1.1,2.3-.7.9.5,1.1,1.5.7,2.4Z",
1232
+ "M31.9,18c3.4-.5,6.9,0,10,1.9l.8.5h0c.8.5,1,1.5.6,2.3s-1.5,1.1-2.3.6l-.8-.5c-2.8-1.6-6-1.9-8.9-1.2-1,.3-2,.7-3,1.2h0c-.8.5-1.8.2-2.3-.7-.5-.8-.2-1.8.6-2.3,0,0,0,0,.2,0,.2,0,.4-.2.7-.3,1.4-.7,2.9-1.1,4.4-1.4Z",
1233
+ "M21.4,24.9c.5-.8,1.6-1,2.3-.5.8.5,1,1.6.5,2.3-.5.8-1.6,1-2.4.5-.8-.5-1-1.6-.5-2.3Z",
1234
+ "M45.5,23.9c.5-.9,1.5-1.1,2.3-.7.8.5,1.1,1.5.6,2.4-.5.8-1.5,1.1-2.3.6s-1.1-1.5-.6-2.3Z",
1235
+ "M49.4,39.9c-3.3.6-6.9,0-10-1.8l-.8-.5h0c-.8-.5-1.1-1.5-.6-2.3s1.5-1.1,2.3-.6l.8.5c2.8,1.6,6,1.9,9,1.2,1-.3,2-.7,3-1.2h0c.8-.5,1.8-.2,2.3.6.5.9.2,1.9-.6,2.4,0,0-.1,0-.2,0-.2.1-.5.3-.7.4-1.4.7-2.8,1.1-4.4,1.4Z",
1236
+ "M35.8,34c-.5.8-1.5,1.1-2.3.6s-1.1-1.5-.6-2.3,1.5-1.1,2.3-.6,1.1,1.5.6,2.3Z"
1237
+ ];
1238
+ function lockup(height) {
1239
+ const node = svg("0 0 240 58.5", {
1240
+ height: String(height),
1241
+ width: String(Math.round(height * (240 / 58.5)))
1242
+ });
1243
+ node.removeAttribute("aria-hidden");
1244
+ node.setAttribute("role", "img");
1245
+ node.setAttribute("aria-label", "ZOREAL");
1246
+ node.appendChild(path(WORDMARK, { fill: "currentColor" }));
1247
+ const g = document.createElementNS(SVG_NS, "g");
1248
+ g.setAttribute("fill", ZOREAL_BLUE);
1249
+ g.setAttribute("fill-rule", "evenodd");
1250
+ for (const d of MARK_PATHS) g.appendChild(path(d));
1251
+ node.appendChild(g);
1252
+ return node;
1253
+ }
1254
+ function mountPairingModal(state, options) {
1255
+ if (typeof document === "undefined") return null;
1256
+ ensureStyles();
1257
+ const t = strings(options.locale);
1258
+ const timeoutMs = options.timeoutMs ?? DEFAULT_PAIRING_TIMEOUT_MS;
1259
+ let closed = false;
1260
+ const scrim = el("div", `${cx("root")} ${cx("scrim")}`);
1261
+ scrim.dataset.theme = options.theme ?? "auto";
1262
+ const card = el("div", cx("card"));
1263
+ card.setAttribute("role", "dialog");
1264
+ card.setAttribute("aria-modal", "true");
1265
+ card.dir = isRtl(options.locale) ? "rtl" : "ltr";
1266
+ const titleId = `zrl-title-${Math.random().toString(36).slice(2, 9)}`;
1267
+ card.setAttribute("aria-labelledby", titleId);
1268
+ const closeBtn = el("button", cx("close"));
1269
+ closeBtn.type = "button";
1270
+ closeBtn.setAttribute("aria-label", t.close);
1271
+ closeBtn.appendChild(strokeIcon(16, ["M18 6 6 18M6 6l12 12"]));
1272
+ const body = el("div", cx("body"));
1273
+ const mark = lockup(44);
1274
+ mark.classList.add(cx("lockup"));
1275
+ const title = el("h2", cx("title"));
1276
+ title.id = titleId;
1277
+ const bodyText = el("p", cx("body-text"));
1278
+ const well = el("div", cx("qr-well"));
1279
+ const qr = el("img", cx("qr"));
1280
+ qr.alt = t.qrAlt;
1281
+ qr.width = 180;
1282
+ qr.height = 180;
1283
+ if (state.qrUrl) qr.src = state.qrUrl;
1284
+ const overlay = el("span", cx("qr-overlay"));
1285
+ const badge = el("span", cx("qr-badge"));
1286
+ badge.appendChild(strokeIcon(24, ["M8.5 2h7a2.5 2.5 0 0 1 2.5 2.5v15a2.5 2.5 0 0 1-2.5 2.5h-7A2.5 2.5 0 0 1 6 19.5v-15A2.5 2.5 0 0 1 8.5 2Z", "M11 18.5h2"], "1.8"));
1287
+ overlay.appendChild(badge);
1288
+ well.append(qr, overlay);
1289
+ const status = el("div", cx("status"));
1290
+ const dot = el("span", cx("dot"));
1291
+ dot.append(el("i"), el("i"));
1292
+ const statusLabel = el("span");
1293
+ status.append(dot, statusLabel);
1294
+ const timer = el("p", cx("timer"));
1295
+ body.append(mark, title, bodyText, well, status, timer);
1296
+ const help = el("div", cx("help"));
1297
+ help.append(el("p", cx("help-title"), t.noIdTitle), el("p", cx("help-body"), t.noIdBody));
1298
+ const footer = el("div", cx("footer"));
1299
+ const cancelBtn = el("button", cx("cancel"), t.cancel);
1300
+ cancelBtn.type = "button";
1301
+ const secured = el("p", cx("secured"));
1302
+ secured.append(strokeIcon(13, ["M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z", "m9 12 2 2 4-4"]), document.createTextNode(t.secured));
1303
+ footer.append(cancelBtn, secured);
1304
+ card.append(closeBtn, body, help, footer);
1305
+ scrim.appendChild(card);
1306
+ const serverMs = typeof state.expiresIn === "number" ? state.expiresIn * 1e3 : Infinity;
1307
+ const deadline = Date.now() + Math.min(timeoutMs, serverMs);
1308
+ const paint = (s) => {
1309
+ const settled = s.status === "claimed" || s.status === "enrolling";
1310
+ title.textContent = settled ? t.titleApprove : t.title;
1311
+ bodyText.textContent = s.status === "enrolling" ? t.bodyEnrolling : settled ? t.bodyApprove : t.bodyScan;
1312
+ statusLabel.textContent = settled ? t.waitingApproval : t.waiting;
1313
+ qr.dataset.spent = String(settled);
1314
+ overlay.style.display = settled ? "" : "none";
1315
+ if (s.qrUrl && qr.src !== s.qrUrl) qr.src = s.qrUrl;
1316
+ };
1317
+ const tick = () => {
1318
+ const left = Math.max(0, Math.ceil((deadline - Date.now()) / 1e3));
1319
+ timer.textContent = interpolate(t.expiresIn, mmss(left));
1320
+ timer.dataset.urgent = String(left <= URGENT_SECONDS);
1321
+ if (left === 0) {
1322
+ window.clearInterval(interval);
1323
+ options.onCancel();
1324
+ }
1325
+ };
1326
+ const onKey = (e) => {
1327
+ if (e.key === "Escape") options.onCancel();
1328
+ };
1329
+ const close = () => {
1330
+ if (closed) return;
1331
+ closed = true;
1332
+ window.clearInterval(interval);
1333
+ document.removeEventListener("keydown", onKey);
1334
+ document.body.style.overflow = previousOverflow;
1335
+ scrim.remove();
1336
+ };
1337
+ closeBtn.addEventListener("click", options.onCancel);
1338
+ cancelBtn.addEventListener("click", options.onCancel);
1339
+ scrim.addEventListener("click", (e) => {
1340
+ if (e.target === scrim) options.onCancel();
1341
+ });
1342
+ document.addEventListener("keydown", onKey);
1343
+ const previousOverflow = document.body.style.overflow;
1344
+ document.body.style.overflow = "hidden";
1345
+ paint(state);
1346
+ tick();
1347
+ const interval = window.setInterval(tick, 1e3);
1348
+ document.body.appendChild(scrim);
1349
+ closeBtn.focus();
1350
+ return { update: paint, close };
1351
+ }
1352
+
182
1353
  // src/pkce.ts
183
1354
  var VERIFIER_BYTES = 32;
184
1355
  var base64url = (bytes) => btoa(String.fromCharCode(...bytes)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
@@ -209,23 +1380,32 @@ function startLogin(options) {
209
1380
  const controller = new AbortController();
210
1381
  const surface = {};
211
1382
  const cancel = () => controller.abort();
1383
+ let modal = null;
1384
+ const closeModal = () => {
1385
+ modal?.close();
1386
+ modal = null;
1387
+ };
212
1388
  const run = async () => {
213
1389
  const verifier = generateVerifier();
214
1390
  const state = generateState();
215
1391
  const nonce = generateState();
216
1392
  try {
217
- const started = await startPairing(issuer, {
218
- client_id: options.clientId,
219
- scope: options.scope ?? "openid",
220
- state,
221
- nonce,
222
- code_challenge: await challengeS256(verifier),
223
- redirect_uri: flow === "auth-code" ? options.redirect_uri : void 0,
224
- acr_values: Array.isArray(options.acr_values) ? options.acr_values.join(" ") : options.acr_values,
225
- max_age: options.max_age,
226
- prompt: options.prompt,
227
- locale: options.locale
228
- });
1393
+ const started = await startPairing(
1394
+ issuer,
1395
+ {
1396
+ client_id: options.clientId,
1397
+ scope: options.scope ?? "openid",
1398
+ state,
1399
+ nonce,
1400
+ code_challenge: await challengeS256(verifier),
1401
+ redirect_uri: flow === "auth-code" ? options.redirect_uri : void 0,
1402
+ acr_values: Array.isArray(options.acr_values) ? options.acr_values.join(" ") : options.acr_values,
1403
+ max_age: options.max_age,
1404
+ prompt: options.prompt,
1405
+ locale: options.locale
1406
+ },
1407
+ controller.signal
1408
+ );
229
1409
  let code;
230
1410
  let selectBy = "device";
231
1411
  if ("code" in started) {
@@ -244,17 +1424,31 @@ function startLogin(options) {
244
1424
  appLink: useAppLink,
245
1425
  cancel
246
1426
  };
247
- options.onState?.({ status: "pending", expiresIn: started.expires_in, ...stateSurface });
1427
+ const initial = { status: "pending", expiresIn: started.expires_in, ...stateSurface };
1428
+ options.onState?.(initial);
1429
+ if ((options.pairingUI ?? "modal") === "modal" && !useAppLink) {
1430
+ modal = mountPairingModal(initial, {
1431
+ onCancel: cancel,
1432
+ locale: options.locale,
1433
+ theme: options.theme,
1434
+ timeoutMs: options.pairingTimeoutMs
1435
+ });
1436
+ }
248
1437
  if (useAppLink && typeof window !== "undefined") {
249
1438
  window.location.assign(started.pair_url);
250
1439
  }
251
1440
  code = await pollUntilApproved(
252
1441
  issuer,
253
1442
  started.request_id,
254
- (s) => options.onState?.({ ...s, ...stateSurface }),
1443
+ (s) => {
1444
+ const next = { ...s, ...stateSurface };
1445
+ modal?.update(next);
1446
+ options.onState?.(next);
1447
+ },
255
1448
  controller.signal
256
1449
  );
257
1450
  }
1451
+ closeModal();
258
1452
  if (flow === "auth-code") {
259
1453
  const response2 = {
260
1454
  code,
@@ -279,6 +1473,7 @@ function startLogin(options) {
279
1473
  };
280
1474
  return response;
281
1475
  } catch (e) {
1476
+ closeModal();
282
1477
  if (e instanceof DOMException && e.name === "AbortError") throw e;
283
1478
  if (e instanceof OAuthFlowError || e instanceof FlowAbandonedError) throw e;
284
1479
  throw new FlowAbandonedError({
@@ -310,6 +1505,7 @@ function startLogin(options) {
310
1505
  // Annotate the CommonJS export names for ESM import in node:
311
1506
  0 && (module.exports = {
312
1507
  DEFAULT_ISSUER,
1508
+ DEFAULT_PAIRING_TIMEOUT_MS,
313
1509
  FlowAbandonedError,
314
1510
  OAuthFlowError,
315
1511
  POLL_INTERVAL_ENROLLING_MS,
@@ -322,6 +1518,7 @@ function startLogin(options) {
322
1518
  generateState,
323
1519
  generateVerifier,
324
1520
  isMobileUserAgent,
1521
+ mountPairingModal,
325
1522
  pollUntilApproved,
326
1523
  startLogin,
327
1524
  startPairing,