@prosopo/locale 3.6.2 → 3.8.0

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.
Files changed (106) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +3 -6
  2. package/.turbo/turbo-build$colon$tsc.log +6 -9
  3. package/.turbo/turbo-build.log +5 -11
  4. package/CHANGELOG.md +43 -0
  5. package/LICENSE +201 -0
  6. package/dist/cjs/locales/en/translation.cjs +24 -2
  7. package/dist/locales/ar/translation.json +24 -2
  8. package/dist/locales/az/translation.json +24 -2
  9. package/dist/locales/cs/translation.json +24 -2
  10. package/dist/locales/de/translation.json +24 -2
  11. package/dist/locales/el/translation.json +24 -2
  12. package/dist/locales/en/translation.js +24 -2
  13. package/dist/locales/en/translation.json +24 -2
  14. package/dist/locales/es/translation.json +24 -2
  15. package/dist/locales/fi/translation.json +24 -2
  16. package/dist/locales/fr/translation.json +24 -2
  17. package/dist/locales/hi/translation.json +24 -2
  18. package/dist/locales/hu/translation.json +24 -2
  19. package/dist/locales/id/translation.json +24 -2
  20. package/dist/locales/it/translation.json +24 -2
  21. package/dist/locales/ja/translation.json +24 -2
  22. package/dist/locales/jv/translation.json +24 -2
  23. package/dist/locales/ko/translation.json +24 -2
  24. package/dist/locales/ml/translation.json +24 -2
  25. package/dist/locales/ms/translation.json +24 -2
  26. package/dist/locales/nl/translation.json +24 -2
  27. package/dist/locales/no/translation.json +24 -2
  28. package/dist/locales/pl/translation.json +24 -2
  29. package/dist/locales/pt/translation.json +24 -2
  30. package/dist/locales/pt-BR/translation.json +24 -2
  31. package/dist/locales/ro/translation.json +24 -2
  32. package/dist/locales/ru/translation.json +24 -2
  33. package/dist/locales/sr/translation.json +24 -2
  34. package/dist/locales/sv/translation.json +24 -2
  35. package/dist/locales/th/translation.json +24 -2
  36. package/dist/locales/tr/translation.json +24 -2
  37. package/dist/locales/uk/translation.json +24 -2
  38. package/dist/locales/vi/translation.json +24 -2
  39. package/dist/locales/zh-CN/translation.json +24 -2
  40. package/package.json +65 -66
  41. package/src/direction.ts +0 -36
  42. package/src/errorMessage.ts +0 -37
  43. package/src/i18SharedOptions.ts +0 -29
  44. package/src/i18nBackend.ts +0 -69
  45. package/src/i18nFrontend.ts +0 -267
  46. package/src/i18nMiddleware.ts +0 -35
  47. package/src/index.ts +0 -33
  48. package/src/loadI18next.ts +0 -136
  49. package/src/locales/ar/translation.json +0 -493
  50. package/src/locales/az/translation.json +0 -493
  51. package/src/locales/cs/translation.json +0 -493
  52. package/src/locales/de/translation.json +0 -493
  53. package/src/locales/el/translation.json +0 -493
  54. package/src/locales/en/translation.json +0 -493
  55. package/src/locales/es/translation.json +0 -493
  56. package/src/locales/fi/translation.json +0 -493
  57. package/src/locales/fr/translation.json +0 -493
  58. package/src/locales/hi/translation.json +0 -493
  59. package/src/locales/hu/translation.json +0 -493
  60. package/src/locales/id/translation.json +0 -493
  61. package/src/locales/it/translation.json +0 -493
  62. package/src/locales/ja/translation.json +0 -493
  63. package/src/locales/jv/translation.json +0 -493
  64. package/src/locales/ko/translation.json +0 -493
  65. package/src/locales/ml/translation.json +0 -493
  66. package/src/locales/ms/translation.json +0 -493
  67. package/src/locales/nl/translation.json +0 -493
  68. package/src/locales/no/translation.json +0 -493
  69. package/src/locales/pl/translation.json +0 -493
  70. package/src/locales/pt/translation.json +0 -493
  71. package/src/locales/pt-BR/translation.json +0 -493
  72. package/src/locales/ro/translation.json +0 -493
  73. package/src/locales/ru/translation.json +0 -493
  74. package/src/locales/sr/translation.json +0 -493
  75. package/src/locales/sv/translation.json +0 -493
  76. package/src/locales/th/translation.json +0 -493
  77. package/src/locales/tr/translation.json +0 -493
  78. package/src/locales/uk/translation.json +0 -493
  79. package/src/locales/vi/translation.json +0 -493
  80. package/src/locales/zh-CN/translation.json +0 -493
  81. package/src/process.ts +0 -29
  82. package/src/tests/direction.unit.test.ts +0 -52
  83. package/src/tests/errorMessage.unit.test.ts +0 -84
  84. package/src/tests/i18SharedOptions.unit.test.ts +0 -139
  85. package/src/tests/i18nBackend.unit.test.ts +0 -241
  86. package/src/tests/i18nFrontend.unit.test.ts +0 -404
  87. package/src/tests/i18nMiddleware.unit.test.ts +0 -159
  88. package/src/tests/loadI18next.unit.test.ts +0 -443
  89. package/src/tests/locale.test-d.ts +0 -184
  90. package/src/tests/localePlaceholders.unit.test.ts +0 -81
  91. package/src/tests/locales.unit.test.ts +0 -79
  92. package/src/tests/process.unit.test.ts +0 -33
  93. package/src/tests/thrownErrorKeys.unit.test.ts +0 -91
  94. package/src/tests/translationKey.unit.test.ts +0 -155
  95. package/src/tests/translations.unit.test.ts +0 -97
  96. package/src/tests/translator.unit.test.ts +0 -213
  97. package/src/tests/util.unit.test.ts +0 -102
  98. package/src/translationKey.ts +0 -73
  99. package/src/translations.ts +0 -55
  100. package/src/translator.ts +0 -69
  101. package/src/types.ts +0 -47
  102. package/src/util.ts +0 -25
  103. package/tsconfig.cjs.json +0 -21
  104. package/tsconfig.json +0 -22
  105. package/tsconfig.tsbuildinfo +0 -1
  106. package/tsconfig.types.json +0 -9
@@ -398,8 +398,30 @@
398
398
  "KEYBOARD_HINT": "Померајте део стрелицама, уз држање тастера Shift за ситније кораке. Притисните Enter да га пошаљете, Home да га вратите на почетак или Escape да откажете.",
399
399
  "POSITION": "{{x}} посто с лева, {{y}} посто одозго",
400
400
  "CHECKING": "Проверавамо ваш одговор",
401
- "RETRY_ANNOUNCEMENT": "За длаку. Учитана је нова слагалица и део је поново на почетку."
402
- }
401
+ "RETRY_ANNOUNCEMENT": "За длаку. Учитана је нова слагалица и део је поново на почетку.",
402
+ "REFRESH": "Друга слагалица"
403
+ },
404
+ "ICON_ORDER": {
405
+ "DIALOG_LABEL": "Изазов редоследа иконица",
406
+ "SELECT": "Изаберите овим редоследом",
407
+ "RETRY": "За длаку — покушајте поново",
408
+ "LEGEND_ALT": "Иконице за избор, по редоследу",
409
+ "RESET": "Поништи",
410
+ "CHECKING": "Провера…",
411
+ "SUBMIT": "У реду"
412
+ },
413
+ "AUDIO_CHALLENGE_LABEL": "Audio verification challenge",
414
+ "AUDIO_INSTRUCTIONS": "Listen and type the {{count}} digits you hear.",
415
+ "AUDIO_INPUT_LABEL": "Type the {{count}} digits you hear",
416
+ "AUDIO_PLAY": "Play",
417
+ "AUDIO_REPLAY": "Play again",
418
+ "AUDIO_PLAYING": "Playing",
419
+ "AUDIO_FINISHED": "Playback finished",
420
+ "AUDIO_PLAYBACK_FAILED": "Audio could not be played. Check your device volume and try again.",
421
+ "AUDIO_INCORRECT": "That wasn't right. Here's a new one.",
422
+ "AUDIO_SUBMIT": "Verify",
423
+ "AUDIO_CHECKING": "Checking",
424
+ "AUDIO_ALTERNATIVE": "Use audio instead"
403
425
  },
404
426
  "CONTRACT": {
405
427
  "INVALID_ADDRESS": "Немогуће кодирање неважеће адресе",
@@ -398,8 +398,30 @@
398
398
  "KEYBOARD_HINT": "Flytta biten med piltangenterna, håll ned skift för mindre steg. Tryck på Retur för att skicka in den, Home för att lägga tillbaka den vid starten, eller Escape för att avbryta.",
399
399
  "POSITION": "{{x}} procent från vänster, {{y}} procent uppifrån",
400
400
  "CHECKING": "Kontrollerar ditt svar",
401
- "RETRY_ANNOUNCEMENT": "Nästan. Ett nytt pussel har laddats och biten är tillbaka vid starten."
402
- }
401
+ "RETRY_ANNOUNCEMENT": "Nästan. Ett nytt pussel har laddats och biten är tillbaka vid starten.",
402
+ "REFRESH": "Ett annat pussel"
403
+ },
404
+ "ICON_ORDER": {
405
+ "DIALOG_LABEL": "Utmaning med ikonordning",
406
+ "SELECT": "Välj i den här ordningen",
407
+ "RETRY": "Nästan — försök igen",
408
+ "LEGEND_ALT": "Ikoner att välja, i ordning",
409
+ "RESET": "Återställ",
410
+ "CHECKING": "Kontrollerar…",
411
+ "SUBMIT": "OK"
412
+ },
413
+ "AUDIO_CHALLENGE_LABEL": "Audio verification challenge",
414
+ "AUDIO_INSTRUCTIONS": "Listen and type the {{count}} digits you hear.",
415
+ "AUDIO_INPUT_LABEL": "Type the {{count}} digits you hear",
416
+ "AUDIO_PLAY": "Play",
417
+ "AUDIO_REPLAY": "Play again",
418
+ "AUDIO_PLAYING": "Playing",
419
+ "AUDIO_FINISHED": "Playback finished",
420
+ "AUDIO_PLAYBACK_FAILED": "Audio could not be played. Check your device volume and try again.",
421
+ "AUDIO_INCORRECT": "That wasn't right. Here's a new one.",
422
+ "AUDIO_SUBMIT": "Verify",
423
+ "AUDIO_CHECKING": "Checking",
424
+ "AUDIO_ALTERNATIVE": "Use audio instead"
403
425
  },
404
426
  "CONTRACT": {
405
427
  "INVALID_ADDRESS": "Misslyckades att koda ogiltig adress",
@@ -398,8 +398,30 @@
398
398
  "KEYBOARD_HINT": "ใช้ปุ่มลูกศรเพื่อเลื่อนชิ้นส่วน กดปุ่ม Shift ค้างไว้เพื่อเลื่อนทีละน้อย กด Enter เพื่อส่ง กด Home เพื่อกลับไปยังจุดเริ่มต้น หรือกด Escape เพื่อยกเลิก",
399
399
  "POSITION": "{{x}} เปอร์เซ็นต์จากด้านซ้าย {{y}} เปอร์เซ็นต์จากด้านบน",
400
400
  "CHECKING": "กำลังตรวจคำตอบของคุณ",
401
- "RETRY_ANNOUNCEMENT": "เกือบแล้ว มีจิ๊กซอว์ชุดใหม่โหลดขึ้นมา และชิ้นส่วนกลับไปอยู่ที่จุดเริ่มต้น"
402
- }
401
+ "RETRY_ANNOUNCEMENT": "เกือบแล้ว มีจิ๊กซอว์ชุดใหม่โหลดขึ้นมา และชิ้นส่วนกลับไปอยู่ที่จุดเริ่มต้น",
402
+ "REFRESH": "จิ๊กซอว์ชุดอื่น"
403
+ },
404
+ "ICON_ORDER": {
405
+ "DIALOG_LABEL": "ภารกิจเรียงลำดับไอคอน",
406
+ "SELECT": "เลือกตามลำดับนี้",
407
+ "RETRY": "เกือบแล้ว — ลองอีกครั้ง",
408
+ "LEGEND_ALT": "ไอคอนที่ต้องเลือกตามลำดับ",
409
+ "RESET": "รีเซ็ต",
410
+ "CHECKING": "กำลังตรวจสอบ…",
411
+ "SUBMIT": "ตกลง"
412
+ },
413
+ "AUDIO_CHALLENGE_LABEL": "Audio verification challenge",
414
+ "AUDIO_INSTRUCTIONS": "Listen and type the {{count}} digits you hear.",
415
+ "AUDIO_INPUT_LABEL": "Type the {{count}} digits you hear",
416
+ "AUDIO_PLAY": "Play",
417
+ "AUDIO_REPLAY": "Play again",
418
+ "AUDIO_PLAYING": "Playing",
419
+ "AUDIO_FINISHED": "Playback finished",
420
+ "AUDIO_PLAYBACK_FAILED": "Audio could not be played. Check your device volume and try again.",
421
+ "AUDIO_INCORRECT": "That wasn't right. Here's a new one.",
422
+ "AUDIO_SUBMIT": "Verify",
423
+ "AUDIO_CHECKING": "Checking",
424
+ "AUDIO_ALTERNATIVE": "Use audio instead"
403
425
  },
404
426
  "CONTRACT": {
405
427
  "INVALID_ADDRESS": "ล้มเหลวในการเข้ารหัสที่อยู่ไม่ถูกต้อง",
@@ -398,8 +398,30 @@
398
398
  "KEYBOARD_HINT": "Parçayı ok tuşlarıyla taşıyın, daha küçük adımlar için Shift tuşunu basılı tutun. Göndermek için Enter'a, başa döndürmek için Home'a, iptal etmek için Escape'e basın.",
399
399
  "POSITION": "soldan yüzde {{x}}, yukarıdan yüzde {{y}}",
400
400
  "CHECKING": "Cevabınız kontrol ediliyor",
401
- "RETRY_ANNOUNCEMENT": "Az kaldı. Yeni bir yapboz yüklendi ve parça yeniden başlangıçta."
402
- }
401
+ "RETRY_ANNOUNCEMENT": "Az kaldı. Yeni bir yapboz yüklendi ve parça yeniden başlangıçta.",
402
+ "REFRESH": "Başka bir yapboz"
403
+ },
404
+ "ICON_ORDER": {
405
+ "DIALOG_LABEL": "Simge sırası görevi",
406
+ "SELECT": "Bu sırayla seçin",
407
+ "RETRY": "Az kaldı — tekrar deneyin",
408
+ "LEGEND_ALT": "Seçilecek simgeler, sırayla",
409
+ "RESET": "Sıfırla",
410
+ "CHECKING": "Kontrol ediliyor…",
411
+ "SUBMIT": "Tamam"
412
+ },
413
+ "AUDIO_CHALLENGE_LABEL": "Audio verification challenge",
414
+ "AUDIO_INSTRUCTIONS": "Listen and type the {{count}} digits you hear.",
415
+ "AUDIO_INPUT_LABEL": "Type the {{count}} digits you hear",
416
+ "AUDIO_PLAY": "Play",
417
+ "AUDIO_REPLAY": "Play again",
418
+ "AUDIO_PLAYING": "Playing",
419
+ "AUDIO_FINISHED": "Playback finished",
420
+ "AUDIO_PLAYBACK_FAILED": "Audio could not be played. Check your device volume and try again.",
421
+ "AUDIO_INCORRECT": "That wasn't right. Here's a new one.",
422
+ "AUDIO_SUBMIT": "Verify",
423
+ "AUDIO_CHECKING": "Checking",
424
+ "AUDIO_ALTERNATIVE": "Use audio instead"
403
425
  },
404
426
  "CONTRACT": {
405
427
  "INVALID_ADDRESS": "Geçersiz adresi kodlama başarısız oldu",
@@ -398,8 +398,30 @@
398
398
  "KEYBOARD_HINT": "Переміщуйте фрагмент клавішами зі стрілками, утримуйте Shift для менших кроків. Натисніть Enter, щоб надіслати, Home, щоб повернути його на початок, або Escape, щоб скасувати.",
399
399
  "POSITION": "{{x}} відсотків зліва, {{y}} відсотків згори",
400
400
  "CHECKING": "Перевіряємо вашу відповідь",
401
- "RETRY_ANNOUNCEMENT": "Майже. Завантажено новий пазл, і фрагмент знову на початку."
402
- }
401
+ "RETRY_ANNOUNCEMENT": "Майже. Завантажено новий пазл, і фрагмент знову на початку.",
402
+ "REFRESH": "Інший пазл"
403
+ },
404
+ "ICON_ORDER": {
405
+ "DIALOG_LABEL": "Завдання на порядок значків",
406
+ "SELECT": "Виберіть у цьому порядку",
407
+ "RETRY": "Майже — спробуйте ще раз",
408
+ "LEGEND_ALT": "Значки для вибору, по порядку",
409
+ "RESET": "Скинути",
410
+ "CHECKING": "Перевірка…",
411
+ "SUBMIT": "OK"
412
+ },
413
+ "AUDIO_CHALLENGE_LABEL": "Audio verification challenge",
414
+ "AUDIO_INSTRUCTIONS": "Listen and type the {{count}} digits you hear.",
415
+ "AUDIO_INPUT_LABEL": "Type the {{count}} digits you hear",
416
+ "AUDIO_PLAY": "Play",
417
+ "AUDIO_REPLAY": "Play again",
418
+ "AUDIO_PLAYING": "Playing",
419
+ "AUDIO_FINISHED": "Playback finished",
420
+ "AUDIO_PLAYBACK_FAILED": "Audio could not be played. Check your device volume and try again.",
421
+ "AUDIO_INCORRECT": "That wasn't right. Here's a new one.",
422
+ "AUDIO_SUBMIT": "Verify",
423
+ "AUDIO_CHECKING": "Checking",
424
+ "AUDIO_ALTERNATIVE": "Use audio instead"
403
425
  },
404
426
  "CONTRACT": {
405
427
  "INVALID_ADDRESS": "Failed to encode invalid address",
@@ -398,8 +398,30 @@
398
398
  "KEYBOARD_HINT": "Dùng các phím mũi tên để di chuyển mảnh ghép, giữ Shift để đi từng bước nhỏ hơn. Nhấn Enter để gửi, Home để đưa nó về vị trí ban đầu, hoặc Escape để hủy.",
399
399
  "POSITION": "{{x}} phần trăm từ bên trái, {{y}} phần trăm từ trên xuống",
400
400
  "CHECKING": "Đang kiểm tra câu trả lời của bạn",
401
- "RETRY_ANNOUNCEMENT": "Suýt nữa. Một hình ghép mới đã được tải và mảnh ghép trở lại vị trí ban đầu."
402
- }
401
+ "RETRY_ANNOUNCEMENT": "Suýt nữa. Một hình ghép mới đã được tải và mảnh ghép trở lại vị trí ban đầu.",
402
+ "REFRESH": "Hình ghép khác"
403
+ },
404
+ "ICON_ORDER": {
405
+ "DIALOG_LABEL": "Thử thách thứ tự biểu tượng",
406
+ "SELECT": "Chọn theo thứ tự này",
407
+ "RETRY": "Suýt nữa — hãy thử lại",
408
+ "LEGEND_ALT": "Các biểu tượng cần chọn, theo thứ tự",
409
+ "RESET": "Đặt lại",
410
+ "CHECKING": "Đang kiểm tra…",
411
+ "SUBMIT": "OK"
412
+ },
413
+ "AUDIO_CHALLENGE_LABEL": "Audio verification challenge",
414
+ "AUDIO_INSTRUCTIONS": "Listen and type the {{count}} digits you hear.",
415
+ "AUDIO_INPUT_LABEL": "Type the {{count}} digits you hear",
416
+ "AUDIO_PLAY": "Play",
417
+ "AUDIO_REPLAY": "Play again",
418
+ "AUDIO_PLAYING": "Playing",
419
+ "AUDIO_FINISHED": "Playback finished",
420
+ "AUDIO_PLAYBACK_FAILED": "Audio could not be played. Check your device volume and try again.",
421
+ "AUDIO_INCORRECT": "That wasn't right. Here's a new one.",
422
+ "AUDIO_SUBMIT": "Verify",
423
+ "AUDIO_CHECKING": "Checking",
424
+ "AUDIO_ALTERNATIVE": "Use audio instead"
403
425
  },
404
426
  "CONTRACT": {
405
427
  "INVALID_ADDRESS": "Không thể mã hóa địa chỉ không hợp lệ",
@@ -398,8 +398,30 @@
398
398
  "KEYBOARD_HINT": "用方向键移动拼块,按住 Shift 可以小步移动。按 Enter 提交,按 Home 让它回到起点,按 Escape 取消。",
399
399
  "POSITION": "距左边 {{x}} %,距顶部 {{y}} %",
400
400
  "CHECKING": "正在检查您的答案",
401
- "RETRY_ANNOUNCEMENT": "差一点。已加载新的拼图,拼块回到了起点。"
402
- }
401
+ "RETRY_ANNOUNCEMENT": "差一点。已加载新的拼图,拼块回到了起点。",
402
+ "REFRESH": "换一个拼图"
403
+ },
404
+ "ICON_ORDER": {
405
+ "DIALOG_LABEL": "图标顺序验证",
406
+ "SELECT": "请按此顺序选择",
407
+ "RETRY": "差一点 — 请再试一次",
408
+ "LEGEND_ALT": "按顺序需选择的图标",
409
+ "RESET": "重置",
410
+ "CHECKING": "正在检查…",
411
+ "SUBMIT": "确定"
412
+ },
413
+ "AUDIO_CHALLENGE_LABEL": "Audio verification challenge",
414
+ "AUDIO_INSTRUCTIONS": "Listen and type the {{count}} digits you hear.",
415
+ "AUDIO_INPUT_LABEL": "Type the {{count}} digits you hear",
416
+ "AUDIO_PLAY": "Play",
417
+ "AUDIO_REPLAY": "Play again",
418
+ "AUDIO_PLAYING": "Playing",
419
+ "AUDIO_FINISHED": "Playback finished",
420
+ "AUDIO_PLAYBACK_FAILED": "Audio could not be played. Check your device volume and try again.",
421
+ "AUDIO_INCORRECT": "That wasn't right. Here's a new one.",
422
+ "AUDIO_SUBMIT": "Verify",
423
+ "AUDIO_CHECKING": "Checking",
424
+ "AUDIO_ALTERNATIVE": "Use audio instead"
403
425
  },
404
426
  "CONTRACT": {
405
427
  "INVALID_ADDRESS": "无法编码无效地址",
package/package.json CHANGED
@@ -1,67 +1,66 @@
1
1
  {
2
- "name": "@prosopo/locale",
3
- "version": "3.6.2",
4
- "description": "Prosopo locale library",
5
- "type": "module",
6
- "engines": {
7
- "node": "^24",
8
- "npm": "^11"
9
- },
10
- "main": "dist/index.js",
11
- "types": "dist/index.d.ts",
12
- "exports": {
13
- ".": {
14
- "types": "./dist/index.d.ts",
15
- "import": "./dist/index.js",
16
- "require": "./dist/cjs/index.cjs"
17
- },
18
- "./locales/en/translation.json": {
19
- "import": "./dist/locales/en/translation.json",
20
- "require": "./dist/locales/en/translation.json"
21
- }
22
- },
23
- "scripts": {
24
- "clean": "del-cli --verbose dist tsconfig.tsbuildinfo",
25
- "build": "npm run build:cross-env -- --mode ${NODE_ENV:-development}",
26
- "build:cross-env": "vite build --config vite.esm.config.ts",
27
- "build:tsc": "tsc --build --verbose",
28
- "build:cjs": "NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV",
29
- "typecheck": "tsc --project tsconfig.types.json",
30
- "test": "NODE_ENV=${NODE_ENV:-test}; npx vitest run --config ./vite.test.config.ts"
31
- },
32
- "author": "Prosopo Limited",
33
- "license": "Apache-2.0",
34
- "dependencies": {
35
- "@prosopo/util": "3.3.13",
36
- "i18next": "26.4.2",
37
- "i18next-fs-backend": "2.6.8",
38
- "i18next-http-middleware": "3.9.9"
39
- },
40
- "devDependencies": {
41
- "@prosopo/config": "3.4.2",
42
- "@types/node": "22.10.2",
43
- "@vitest/coverage-v8": "4.1.11",
44
- "concurrently": "9.0.1",
45
- "del-cli": "6.0.0",
46
- "dotenv": "16.4.5",
47
- "npm-run-all": "4.1.5",
48
- "tslib": "2.7.0",
49
- "tsx": "4.20.3",
50
- "typescript": "5.6.2",
51
- "vite": "8.1.5",
52
- "vitest": "4.1.11"
53
- },
54
- "repository": {
55
- "type": "git",
56
- "url": "git+https://github.com/prosopo/captcha.git",
57
- "directory": "packages/locale"
58
- },
59
- "bugs": {
60
- "url": "https://github.com/prosopo/captcha/issues"
61
- },
62
- "homepage": "https://github.com/prosopo/captcha#readme",
63
- "publishConfig": {
64
- "registry": "https://registry.npmjs.org"
65
- },
66
- "sideEffects": false
67
- }
2
+ "name": "@prosopo/locale",
3
+ "version": "3.8.0",
4
+ "description": "Prosopo locale library",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": "^24"
8
+ },
9
+ "main": "dist/index.js",
10
+ "types": "dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/cjs/index.cjs"
16
+ },
17
+ "./locales/en/translation.json": {
18
+ "import": "./dist/locales/en/translation.json",
19
+ "require": "./dist/locales/en/translation.json"
20
+ }
21
+ },
22
+ "author": "Prosopo Limited",
23
+ "license": "Apache-2.0",
24
+ "dependencies": {
25
+ "@prosopo/util": "3.3.14",
26
+ "i18next": "26.4.2",
27
+ "i18next-fs-backend": "2.6.8",
28
+ "i18next-http-middleware": "3.9.9"
29
+ },
30
+ "devDependencies": {
31
+ "@prosopo/config": "3.4.3",
32
+ "@types/node": "22.10.2",
33
+ "@vitest/coverage-v8": "4.1.11",
34
+ "concurrently": "9.0.1",
35
+ "del-cli": "6.0.0",
36
+ "dotenv": "16.4.5",
37
+ "npm-run-all": "4.1.5",
38
+ "tslib": "2.7.0",
39
+ "tsx": "4.20.3",
40
+ "typescript": "5.6.2",
41
+ "vite": "8.1.5",
42
+ "vitest": "4.1.11"
43
+ },
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/prosopo/captcha.git",
47
+ "directory": "packages/locale"
48
+ },
49
+ "bugs": {
50
+ "url": "https://github.com/prosopo/captcha/issues"
51
+ },
52
+ "homepage": "https://github.com/prosopo/captcha#readme",
53
+ "publishConfig": {
54
+ "registry": "https://registry.npmjs.org"
55
+ },
56
+ "sideEffects": false,
57
+ "scripts": {
58
+ "clean": "del-cli --verbose dist tsconfig.tsbuildinfo",
59
+ "build": "pnpm run build:cross-env --mode ${NODE_ENV:-development}",
60
+ "build:cross-env": "vite build --config vite.esm.config.ts",
61
+ "build:tsc": "tsc --build --verbose",
62
+ "build:cjs": "NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV",
63
+ "typecheck": "tsc --project tsconfig.types.json",
64
+ "test": "NODE_ENV=${NODE_ENV:-test}; pnpm exec vitest run --config ./vite.test.config.ts"
65
+ }
66
+ }
package/src/direction.ts DELETED
@@ -1,36 +0,0 @@
1
- // Copyright 2021-2026 Prosopo (UK) Ltd.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
-
15
- export type TextDirection = "ltr" | "rtl";
16
-
17
- // Scripts written right to left, by primary language subtag. Wider than the
18
- // shipped catalogues so a site asking for e.g. "he" still gets a mirrored
19
- // layout around whichever fallback text it is served.
20
- const RTL_LANGUAGES: ReadonlySet<string> = new Set([
21
- "ar",
22
- "ckb",
23
- "dv",
24
- "fa",
25
- "he",
26
- "ps",
27
- "sd",
28
- "ug",
29
- "ur",
30
- "yi",
31
- ]);
32
-
33
- export const getLanguageDirection = (language: string): TextDirection => {
34
- const primary = language.split(/[-_]/)[0]?.toLowerCase() ?? "";
35
- return RTL_LANGUAGES.has(primary) ? "rtl" : "ltr";
36
- };
@@ -1,37 +0,0 @@
1
- // Copyright 2021-2026 Prosopo (UK) Ltd.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
- import { isTranslationKey } from "./translationKey.js";
15
- import type { Ti18n } from "./types.js";
16
-
17
- export interface KeyedErrorMessage {
18
- message: string;
19
- key?: string;
20
- }
21
-
22
- /**
23
- * The provider translates error messages into the request's Accept-Language,
24
- * which is the browser's language rather than the widget's. Re-translating the
25
- * error key on the client shows the error in the language the widget renders
26
- * in. Free text and keys the catalogue doesn't have keep the server's message.
27
- */
28
- export const localiseErrorMessage = (
29
- i18n: Ti18n | undefined,
30
- error: KeyedErrorMessage,
31
- ): string => {
32
- const { key, message } = error;
33
- if (!key || !isTranslationKey(key) || !i18n?.isInitialized) {
34
- return message;
35
- }
36
- return i18n.t(key, { defaultValue: message });
37
- };
@@ -1,29 +0,0 @@
1
- // Copyright 2021-2026 Prosopo (UK) Ltd.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
- import { getProcess } from "./process.js";
15
- import { LanguageCodes, Languages } from "./translations.js";
16
-
17
- // Read through getProcess() so the module stays loadable in a plain browser
18
- // runtime where `process` is undefined. Without that guard, any side-effectful
19
- // runtime import of `@prosopo/types` (which transitively reaches here via
20
- // `LanguageSchema`) crashes the page in Vite's dev/preview mode.
21
- const logLevel = getProcess()?.env?.PROSOPO_LOG_LEVEL;
22
-
23
- export const i18nSharedOptions = {
24
- debug: logLevel === "debug",
25
- fallbackLng: Languages.english,
26
- namespace: "translation",
27
- supportedLngs: LanguageCodes,
28
- nonExplicitSupportedLngs: false,
29
- };
@@ -1,69 +0,0 @@
1
- // Copyright 2021-2026 Prosopo (UK) Ltd.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
-
15
- import path from "node:path";
16
- import i18n from "i18next";
17
- import FSBackend from "i18next-fs-backend/cjs"; // https://github.com/i18next/i18next-fs-backend/issues/57
18
- import { LanguageDetector as MiddlewareLanguageDetector } from "i18next-http-middleware";
19
- import { i18nSharedOptions } from "./i18SharedOptions.js";
20
- import { isServerSide } from "./util.js";
21
-
22
- const loadPath =
23
- `${path.dirname(import.meta.url)}/locales/{{lng}}/{{ns}}.json`.replace(
24
- "file://",
25
- "",
26
- );
27
-
28
- export function initializeI18n(
29
- i18nLoadedCallback?: (value: typeof i18n) => void,
30
- ) {
31
- if (!i18n.isInitialized && isServerSide()) {
32
- const lngDetector = new MiddlewareLanguageDetector(null, {
33
- order: ["header", "query", "cookie"],
34
- });
35
- i18n
36
- // @ts-ignore https://github.com/i18next/i18next-fs-backend/issues/57
37
- .use(FSBackend)
38
- .use(lngDetector) // this line should switch the language to the one the user reports in the Accept-Language header
39
- .init({
40
- ...i18nSharedOptions,
41
- ns: ["translation"],
42
- backend: {
43
- loadPath,
44
- },
45
- });
46
- // "loaded" fires once per namespace, and again after changeLanguage(),
47
- // so the raw event is not the one-shot signal the callback expects.
48
- // Latch it here as well as in loadI18next: this callback is public and
49
- // a caller could reasonably use it to run a side effect.
50
- let notified = false;
51
- i18n.on("loaded", () => {
52
- if (notified) {
53
- return;
54
- }
55
- notified = true;
56
- i18nLoadedCallback?.(i18n);
57
- });
58
- } else {
59
- // Nothing to initialise — either i18next is already up (a frontend
60
- // consumer got there first) or we are not on the server. The `loaded`
61
- // handler above is only registered inside the init branch, so without
62
- // this the callback would never fire and loadI18next() would stay
63
- // pending forever instead of handing back the instance we already have.
64
- i18nLoadedCallback?.(i18n);
65
- }
66
- return i18n;
67
- }
68
-
69
- export default initializeI18n;