keycloakify 6.11.9 → 6.12.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 (253) hide show
  1. package/README.md +10 -7
  2. package/bin/create-keycloak-email-directory.js +1 -1
  3. package/bin/download-builtin-keycloak-theme.js +1 -1
  4. package/bin/keycloakify/BuildOptions.d.ts +2 -2
  5. package/bin/keycloakify/BuildOptions.js.map +1 -1
  6. package/bin/keycloakify/generateFtl/generateFtl.d.ts +2 -2
  7. package/bin/keycloakify/generateJavaStackFiles.d.ts +1 -1
  8. package/bin/keycloakify/generateKeycloakThemeResources.d.ts +1 -1
  9. package/bin/keycloakify/generateKeycloakThemeResources.js +1 -1
  10. package/bin/keycloakify/generateStartKeycloakTestingContainer.d.ts +1 -1
  11. package/bin/keycloakify/keycloakify.js +1 -1
  12. package/bin/keycloakify/replacers/replaceImportsFromStaticInJsCode.d.ts +1 -1
  13. package/bin/keycloakify/replacers/replaceImportsInCssCode.d.ts +1 -1
  14. package/bin/keycloakify/replacers/replaceImportsInInlineCssCode.d.ts +1 -1
  15. package/bin/promptKeycloakVersion.js +1 -1
  16. package/bin/tools/NpmModuleVersion.d.ts +1 -1
  17. package/bin/tools/cliOptions.d.ts +1 -1
  18. package/bin/tools/deflate.js +1 -1
  19. package/bin/tools/downloadAndUnzip.js +51 -44
  20. package/bin/tools/downloadAndUnzip.js.map +1 -1
  21. package/bin/tools/grant-exec-perms.js +3 -2
  22. package/bin/tools/grant-exec-perms.js.map +1 -1
  23. package/bin/tools/jar.d.ts +1 -1
  24. package/bin/tools/jar.js +1 -1
  25. package/bin/tools/logger.d.ts +2 -2
  26. package/bin/tools/octokit-addons/getLatestsSemVersionedTag.js +34 -27
  27. package/bin/tools/octokit-addons/getLatestsSemVersionedTag.js.map +1 -1
  28. package/bin/tools/octokit-addons/listTags.js +1 -1
  29. package/bin/tools/transformCodebase.d.ts +1 -1
  30. package/bin/tools/walk.js +1 -1
  31. package/bin/tools/zip.d.ts +2 -2
  32. package/bin/tools/zip.js +1 -1
  33. package/bin/tsconfig.tsbuildinfo +1 -1
  34. package/lib/KcApp.d.ts +6 -0
  35. package/lib/{components/KcApp.js → KcApp.js} +25 -26
  36. package/lib/KcApp.js.map +1 -0
  37. package/lib/{components/KcProps.d.ts → KcProps.d.ts} +30 -6
  38. package/lib/{components/KcProps.js → KcProps.js} +1 -1
  39. package/lib/KcProps.js.map +1 -0
  40. package/lib/Template.d.ts +5 -0
  41. package/lib/{components/Template.js → Template.js} +12 -14
  42. package/lib/Template.js.map +1 -0
  43. package/lib/getKcContext/KcContextBase.d.ts +6 -6
  44. package/lib/getKcContext/getKcContextFromWindow.d.ts +1 -1
  45. package/lib/getKcContext/{kcContextMocks/kcContextMocks.d.ts → kcContextMocks.d.ts} +1 -1
  46. package/lib/getKcContext/{kcContextMocks/kcContextMocks.js → kcContextMocks.js} +8 -5
  47. package/lib/getKcContext/kcContextMocks.js.map +1 -0
  48. package/lib/i18n/i18n.d.ts +100 -0
  49. package/lib/i18n/i18n.js +160 -0
  50. package/lib/i18n/i18n.js.map +1 -0
  51. package/lib/i18n/index.d.ts +1 -99
  52. package/lib/i18n/index.js +1 -159
  53. package/lib/i18n/index.js.map +1 -1
  54. package/lib/index.d.ts +3 -3
  55. package/lib/index.js +3 -3
  56. package/lib/index.js.map +1 -1
  57. package/lib/pages/Error.d.ts +5 -0
  58. package/lib/{components → pages}/Error.js +4 -6
  59. package/lib/pages/Error.js.map +1 -0
  60. package/lib/pages/IdpReviewUserProfile.d.ts +5 -0
  61. package/lib/{components → pages}/IdpReviewUserProfile.js +4 -6
  62. package/lib/pages/IdpReviewUserProfile.js.map +1 -0
  63. package/lib/pages/Info.d.ts +5 -0
  64. package/lib/{components → pages}/Info.js +4 -6
  65. package/lib/pages/Info.js.map +1 -0
  66. package/lib/pages/Login.d.ts +5 -0
  67. package/lib/{components → pages}/Login.js +5 -7
  68. package/lib/pages/Login.js.map +1 -0
  69. package/lib/pages/LoginConfigTotp.d.ts +5 -0
  70. package/lib/{components → pages}/LoginConfigTotp.js +4 -6
  71. package/lib/pages/LoginConfigTotp.js.map +1 -0
  72. package/lib/pages/LoginIdpLinkConfirm.d.ts +5 -0
  73. package/lib/{components → pages}/LoginIdpLinkConfirm.js +4 -6
  74. package/lib/pages/LoginIdpLinkConfirm.js.map +1 -0
  75. package/lib/pages/LoginIdpLinkEmail.d.ts +5 -0
  76. package/lib/{components → pages}/LoginIdpLinkEmail.js +4 -6
  77. package/lib/pages/LoginIdpLinkEmail.js.map +1 -0
  78. package/lib/pages/LoginOtp.d.ts +5 -0
  79. package/lib/{components → pages}/LoginOtp.js +4 -6
  80. package/lib/pages/LoginOtp.js.map +1 -0
  81. package/lib/pages/LoginPageExpired.d.ts +5 -0
  82. package/lib/{components → pages}/LoginPageExpired.js +4 -6
  83. package/lib/pages/LoginPageExpired.js.map +1 -0
  84. package/lib/pages/LoginPassword.d.ts +5 -0
  85. package/lib/{components → pages}/LoginPassword.js +5 -7
  86. package/lib/pages/LoginPassword.js.map +1 -0
  87. package/lib/pages/LoginResetPassword.d.ts +5 -0
  88. package/lib/{components → pages}/LoginResetPassword.js +4 -6
  89. package/lib/pages/LoginResetPassword.js.map +1 -0
  90. package/lib/pages/LoginUpdatePassword.d.ts +5 -0
  91. package/lib/{components → pages}/LoginUpdatePassword.js +4 -6
  92. package/lib/pages/LoginUpdatePassword.js.map +1 -0
  93. package/lib/pages/LoginUpdateProfile.d.ts +5 -0
  94. package/lib/{components → pages}/LoginUpdateProfile.js +4 -6
  95. package/lib/pages/LoginUpdateProfile.js.map +1 -0
  96. package/lib/pages/LoginUsername.d.ts +5 -0
  97. package/lib/{components → pages}/LoginUsername.js +5 -7
  98. package/lib/pages/LoginUsername.js.map +1 -0
  99. package/lib/pages/LoginVerifyEmail.d.ts +5 -0
  100. package/lib/{components → pages}/LoginVerifyEmail.js +4 -6
  101. package/lib/pages/LoginVerifyEmail.js.map +1 -0
  102. package/lib/pages/LogoutConfirm.d.ts +5 -0
  103. package/lib/{components → pages}/LogoutConfirm.js +4 -6
  104. package/lib/pages/LogoutConfirm.js.map +1 -0
  105. package/lib/pages/Register.d.ts +5 -0
  106. package/lib/{components → pages}/Register.js +4 -6
  107. package/lib/pages/Register.js.map +1 -0
  108. package/lib/pages/RegisterUserProfile.d.ts +5 -0
  109. package/lib/{components → pages}/RegisterUserProfile.js +4 -6
  110. package/lib/pages/RegisterUserProfile.js.map +1 -0
  111. package/lib/pages/Terms.d.ts +19 -0
  112. package/lib/{components → pages}/Terms.js +20 -22
  113. package/lib/pages/Terms.js.map +1 -0
  114. package/lib/pages/UpdateUserProfile.d.ts +5 -0
  115. package/lib/{components → pages}/UpdateUserProfile.js +4 -6
  116. package/lib/pages/UpdateUserProfile.js.map +1 -0
  117. package/lib/pages/WebauthnAuthenticate.d.ts +5 -0
  118. package/lib/{components → pages}/WebauthnAuthenticate.js +5 -7
  119. package/lib/pages/WebauthnAuthenticate.js.map +1 -0
  120. package/lib/{components → pages}/shared/UserProfileCommons.d.ts +6 -6
  121. package/lib/{components → pages}/shared/UserProfileCommons.js +4 -4
  122. package/lib/pages/shared/UserProfileCommons.js.map +1 -0
  123. package/lib/tools/AndByDiscriminatingKey.d.ts +1 -1
  124. package/lib/tools/DeepPartial.d.ts +1 -1
  125. package/lib/tools/ReactComponent.d.ts +1 -1
  126. package/lib/tools/SetOptional.d.ts +1 -0
  127. package/lib/tools/SetOptional.js +2 -0
  128. package/lib/tools/SetOptional.js.map +1 -0
  129. package/lib/tools/clsx.d.ts +2 -3
  130. package/lib/tools/clsx.js +39 -3
  131. package/lib/tools/clsx.js.map +1 -1
  132. package/lib/tools/deepAssign.js +1 -1
  133. package/lib/tools/deepAssign.js.map +1 -1
  134. package/lib/tools/memoize.d.ts +7 -0
  135. package/lib/tools/memoize.js +38 -0
  136. package/lib/tools/memoize.js.map +1 -0
  137. package/lib/tools/useCallbackFactory.d.ts +15 -0
  138. package/lib/tools/useCallbackFactory.js +28 -0
  139. package/lib/tools/useCallbackFactory.js.map +1 -0
  140. package/lib/tools/useConst.d.ts +5 -0
  141. package/lib/tools/useConst.js +10 -0
  142. package/lib/tools/useConst.js.map +1 -0
  143. package/lib/tools/useConstCallback.d.ts +2 -0
  144. package/lib/tools/useConstCallback.js +8 -0
  145. package/lib/tools/useConstCallback.js.map +1 -0
  146. package/lib/tools/useCssAndCx.d.ts +1 -1
  147. package/lib/tsconfig.tsbuildinfo +1 -1
  148. package/lib/useFormValidationSlice.d.ts +4 -4
  149. package/lib/useFormValidationSlice.js +1 -1
  150. package/lib/useFormValidationSlice.js.map +1 -1
  151. package/package.json +133 -124
  152. package/src/bin/keycloakify/BuildOptions.ts +2 -2
  153. package/src/bin/keycloakify/generateFtl/generateFtl.ts +1 -1
  154. package/src/lib/{components/KcApp.tsx → KcApp.tsx} +29 -38
  155. package/src/lib/{components/KcProps.ts → KcProps.ts} +27 -1
  156. package/src/lib/{components/Template.tsx → Template.tsx} +23 -38
  157. package/src/lib/getKcContext/KcContextBase.ts +1 -1
  158. package/src/lib/getKcContext/{kcContextMocks/kcContextMocks.ts → kcContextMocks.ts} +9 -6
  159. package/src/lib/i18n/i18n.tsx +292 -0
  160. package/src/lib/i18n/index.tsx +1 -290
  161. package/src/lib/index.ts +3 -3
  162. package/src/lib/{components → pages}/Error.tsx +7 -18
  163. package/src/lib/{components → pages}/IdpReviewUserProfile.tsx +7 -18
  164. package/src/lib/{components → pages}/Info.tsx +7 -18
  165. package/src/lib/{components → pages}/Login.tsx +8 -20
  166. package/src/lib/{components → pages}/LoginConfigTotp.tsx +7 -18
  167. package/src/lib/{components → pages}/LoginIdpLinkConfirm.tsx +7 -18
  168. package/src/lib/{components → pages}/LoginIdpLinkEmail.tsx +7 -18
  169. package/src/lib/{components → pages}/LoginOtp.tsx +7 -18
  170. package/src/lib/{components → pages}/LoginPageExpired.tsx +7 -18
  171. package/src/lib/{components → pages}/LoginPassword.tsx +8 -19
  172. package/src/lib/{components → pages}/LoginResetPassword.tsx +7 -18
  173. package/src/lib/{components → pages}/LoginUpdatePassword.tsx +7 -18
  174. package/src/lib/{components → pages}/LoginUpdateProfile.tsx +7 -18
  175. package/src/lib/{components → pages}/LoginUsername.tsx +8 -19
  176. package/src/lib/{components → pages}/LoginVerifyEmail.tsx +7 -18
  177. package/src/lib/{components → pages}/LogoutConfirm.tsx +7 -18
  178. package/src/lib/{components → pages}/Register.tsx +7 -18
  179. package/src/lib/{components → pages}/RegisterUserProfile.tsx +7 -18
  180. package/src/lib/{components → pages}/Terms.tsx +50 -61
  181. package/src/lib/{components → pages}/UpdateUserProfile.tsx +7 -18
  182. package/src/lib/{components → pages}/WebauthnAuthenticate.tsx +9 -19
  183. package/src/lib/pages/shared/UserProfileCommons.tsx +178 -0
  184. package/src/lib/tools/SetOptional.ts +1 -0
  185. package/src/lib/tools/clsx.ts +42 -5
  186. package/src/lib/tools/deepAssign.ts +1 -1
  187. package/src/lib/tools/memoize.ts +55 -0
  188. package/src/lib/tools/useCallbackFactory.ts +45 -0
  189. package/src/lib/tools/useConst.ts +10 -0
  190. package/src/lib/tools/useConstCallback.ts +15 -0
  191. package/src/lib/useFormValidationSlice.tsx +4 -4
  192. package/bin/generate-i18n-messages.d.ts +0 -1
  193. package/bin/generate-i18n-messages.js +0 -126
  194. package/bin/generate-i18n-messages.js.map +0 -1
  195. package/bin/link_in_test_app.d.ts +0 -1
  196. package/bin/link_in_test_app.js +0 -141
  197. package/bin/link_in_test_app.js.map +0 -1
  198. package/lib/components/Error.d.ts +0 -13
  199. package/lib/components/Error.js.map +0 -1
  200. package/lib/components/IdpReviewUserProfile.d.ts +0 -13
  201. package/lib/components/IdpReviewUserProfile.js.map +0 -1
  202. package/lib/components/Info.d.ts +0 -13
  203. package/lib/components/Info.js.map +0 -1
  204. package/lib/components/KcApp.d.ts +0 -13
  205. package/lib/components/KcApp.js.map +0 -1
  206. package/lib/components/KcProps.js.map +0 -1
  207. package/lib/components/Login.d.ts +0 -13
  208. package/lib/components/Login.js.map +0 -1
  209. package/lib/components/LoginConfigTotp.d.ts +0 -13
  210. package/lib/components/LoginConfigTotp.js.map +0 -1
  211. package/lib/components/LoginIdpLinkConfirm.d.ts +0 -13
  212. package/lib/components/LoginIdpLinkConfirm.js.map +0 -1
  213. package/lib/components/LoginIdpLinkEmail.d.ts +0 -13
  214. package/lib/components/LoginIdpLinkEmail.js.map +0 -1
  215. package/lib/components/LoginOtp.d.ts +0 -13
  216. package/lib/components/LoginOtp.js.map +0 -1
  217. package/lib/components/LoginPageExpired.d.ts +0 -13
  218. package/lib/components/LoginPageExpired.js.map +0 -1
  219. package/lib/components/LoginPassword.d.ts +0 -13
  220. package/lib/components/LoginPassword.js.map +0 -1
  221. package/lib/components/LoginResetPassword.d.ts +0 -13
  222. package/lib/components/LoginResetPassword.js.map +0 -1
  223. package/lib/components/LoginUpdatePassword.d.ts +0 -13
  224. package/lib/components/LoginUpdatePassword.js.map +0 -1
  225. package/lib/components/LoginUpdateProfile.d.ts +0 -13
  226. package/lib/components/LoginUpdateProfile.js.map +0 -1
  227. package/lib/components/LoginUsername.d.ts +0 -13
  228. package/lib/components/LoginUsername.js.map +0 -1
  229. package/lib/components/LoginVerifyEmail.d.ts +0 -13
  230. package/lib/components/LoginVerifyEmail.js.map +0 -1
  231. package/lib/components/LogoutConfirm.d.ts +0 -13
  232. package/lib/components/LogoutConfirm.js.map +0 -1
  233. package/lib/components/Register.d.ts +0 -13
  234. package/lib/components/Register.js.map +0 -1
  235. package/lib/components/RegisterUserProfile.d.ts +0 -13
  236. package/lib/components/RegisterUserProfile.js.map +0 -1
  237. package/lib/components/Template.d.ts +0 -25
  238. package/lib/components/Template.js.map +0 -1
  239. package/lib/components/Terms.d.ts +0 -27
  240. package/lib/components/Terms.js.map +0 -1
  241. package/lib/components/UpdateUserProfile.d.ts +0 -13
  242. package/lib/components/UpdateUserProfile.js.map +0 -1
  243. package/lib/components/WebauthnAuthenticate.d.ts +0 -13
  244. package/lib/components/WebauthnAuthenticate.js.map +0 -1
  245. package/lib/components/shared/UserProfileCommons.js.map +0 -1
  246. package/lib/getKcContext/kcContextMocks/index.d.ts +0 -1
  247. package/lib/getKcContext/kcContextMocks/index.js +0 -2
  248. package/lib/getKcContext/kcContextMocks/index.js.map +0 -1
  249. package/lib/getKcContext/kcContextMocks/kcContextMocks.js.map +0 -1
  250. package/src/bin/generate-i18n-messages.ts +0 -86
  251. package/src/bin/link_in_test_app.ts +0 -128
  252. package/src/lib/components/shared/UserProfileCommons.tsx +0 -173
  253. package/src/lib/getKcContext/kcContextMocks/index.ts +0 -1
@@ -1,32 +1,13 @@
1
- import React, { useReducer, useEffect, memo } from "react";
2
- import type { ReactNode } from "react";
3
- import type { KcContextBase } from "../getKcContext/KcContextBase";
4
- import { assert } from "../tools/assert";
5
- import { useCallbackFactory } from "powerhooks/useCallbackFactory";
6
- import { headInsert } from "../tools/headInsert";
7
- import { pathJoin } from "../../bin/tools/pathJoin";
8
- import { useConstCallback } from "powerhooks/useConstCallback";
9
- import type { KcTemplateProps } from "./KcProps";
10
- import { clsx } from "../tools/clsx";
11
- import type { I18n } from "../i18n";
12
-
13
- export type TemplateProps = {
14
- displayInfo?: boolean;
15
- displayMessage?: boolean;
16
- displayRequiredFields?: boolean;
17
- displayWide?: boolean;
18
- showAnotherWayIfPresent?: boolean;
19
- headerNode: ReactNode;
20
- showUsernameNode?: ReactNode;
21
- formNode: ReactNode;
22
- infoNode?: ReactNode;
23
- /** If you write your own page you probably want
24
- * to avoid pulling the default theme assets.
25
- */
26
- doFetchDefaultThemeResources: boolean;
27
- } & { kcContext: KcContextBase; i18n: I18n } & KcTemplateProps;
28
-
29
- const Template = memo((props: TemplateProps) => {
1
+ import React, { useReducer, useEffect } from "react";
2
+ import { assert } from "./tools/assert";
3
+ import { headInsert } from "./tools/headInsert";
4
+ import { pathJoin } from "../bin/tools/pathJoin";
5
+ import { clsx } from "./tools/clsx";
6
+ import type { TemplateProps } from "./KcProps";
7
+ import type { KcContextBase } from "./getKcContext/KcContextBase";
8
+ import type { I18nBase } from "./i18n";
9
+
10
+ export default function Template(props: TemplateProps<KcContextBase.Common, I18nBase>) {
30
11
  const {
31
12
  displayInfo = false,
32
13
  displayMessage = true,
@@ -44,10 +25,6 @@ const Template = memo((props: TemplateProps) => {
44
25
 
45
26
  const { msg, changeLocale, labelBySupportedLanguageTag, currentLanguageTag } = i18n;
46
27
 
47
- const onChangeLanguageClickFactory = useCallbackFactory(([kcLanguageTag]: [string]) => changeLocale(kcLanguageTag));
48
-
49
- const onTryAnotherWayClick = useConstCallback(() => (document.forms["kc-select-try-another-way-form" as never].submit(), false));
50
-
51
28
  const { realm, locale, auth, url, message, isAppInitiatedAction } = kcContext;
52
29
 
53
30
  const [isExtraCssLoaded, setExtraCssLoaded] = useReducer(() => true, false);
@@ -126,13 +103,15 @@ const Template = memo((props: TemplateProps) => {
126
103
  <div id="kc-locale">
127
104
  <div id="kc-locale-wrapper" className={clsx(props.kcLocaleWrapperClass)}>
128
105
  <div className="kc-dropdown" id="kc-locale-dropdown">
106
+ {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
129
107
  <a href="#" id="kc-current-locale-link">
130
108
  {labelBySupportedLanguageTag[currentLanguageTag]}
131
109
  </a>
132
110
  <ul>
133
111
  {locale.supported.map(({ languageTag }) => (
134
112
  <li key={languageTag} className="kc-dropdown-item">
135
- <a href="#" onClick={onChangeLanguageClickFactory(languageTag)}>
113
+ {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
114
+ <a href="#" onClick={() => changeLocale(languageTag)}>
136
115
  {labelBySupportedLanguageTag[languageTag]}
137
116
  </a>
138
117
  </li>
@@ -225,7 +204,15 @@ const Template = memo((props: TemplateProps) => {
225
204
  <div className={clsx(displayWide && [props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass])}>
226
205
  <div className={clsx(props.kcFormGroupClass)}>
227
206
  <input type="hidden" name="tryAnotherWay" value="on" />
228
- <a href="#" id="try-another-way" onClick={onTryAnotherWayClick}>
207
+ {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
208
+ <a
209
+ href="#"
210
+ id="try-another-way"
211
+ onClick={() => {
212
+ document.forms["kc-select-try-another-way-form" as never].submit();
213
+ return false;
214
+ }}
215
+ >
229
216
  {msg("doTryAnotherWay")}
230
217
  </a>
231
218
  </div>
@@ -244,6 +231,4 @@ const Template = memo((props: TemplateProps) => {
244
231
  </div>
245
232
  </div>
246
233
  );
247
- });
248
-
249
- export default Template;
234
+ }
@@ -2,7 +2,7 @@ import type { PageId } from "../../bin/keycloakify/generateFtl";
2
2
  import { assert } from "tsafe/assert";
3
3
  import type { Equals } from "tsafe";
4
4
  import type { MessageKeyBase } from "../i18n";
5
- import type { KcTemplateClassKey } from "../components/KcProps";
5
+ import type { KcTemplateClassKey } from "../KcProps";
6
6
 
7
7
  type ExtractAfterStartingWith<Prefix extends string, StrEnum> = StrEnum extends `${Prefix}${infer U}` ? U : never;
8
8
 
@@ -1,9 +1,9 @@
1
1
  import "minimal-polyfills/Object.fromEntries";
2
- import type { KcContextBase, Attribute } from "../KcContextBase";
2
+ import type { KcContextBase, Attribute } from "./KcContextBase";
3
3
  //NOTE: Aside because we want to be able to import them from node
4
- import { mockTestingResourcesCommonPath, mockTestingResourcesPath } from "../../../bin/mockTestingResourcesPath";
4
+ import { mockTestingResourcesCommonPath, mockTestingResourcesPath } from "../../bin/mockTestingResourcesPath";
5
5
  import { id } from "tsafe/id";
6
- import { pathJoin } from "../../../bin/tools/pathJoin";
6
+ import { pathJoin } from "../../bin/tools/pathJoin";
7
7
 
8
8
  const PUBLIC_URL = process.env["PUBLIC_URL"] ?? "/";
9
9
 
@@ -117,10 +117,13 @@ export const kcContextCommonMock: KcContextBase.Common = {
117
117
  "registrationEmailAsUsername": false
118
118
  },
119
119
  "messagesPerField": {
120
- "printIfExists": (...[, x]) => x,
121
- "existsError": () => true,
120
+ "printIfExists": () => {
121
+ console.log("coucou");
122
+ return undefined;
123
+ },
124
+ "existsError": () => false,
122
125
  "get": key => `Fake error for ${key}`,
123
- "exists": () => true
126
+ "exists": () => false
124
127
  },
125
128
  "locale": {
126
129
  "supported": [
@@ -0,0 +1,292 @@
1
+ import "minimal-polyfills/Object.fromEntries";
2
+ //NOTE for later: https://github.com/remarkjs/react-markdown/blob/236182ecf30bd89c1e5a7652acaf8d0bf81e6170/src/renderers.js#L7-L35
3
+ import React, { useEffect, useState, useRef } from "react";
4
+ import type baseMessages from "./generated_messages/18.0.1/login/en";
5
+ import { assert } from "tsafe/assert";
6
+ import type { KcContextBase } from "../getKcContext/KcContextBase";
7
+ import { Markdown } from "../tools/Markdown";
8
+
9
+ export const fallbackLanguageTag = "en";
10
+
11
+ export type KcContextLike = {
12
+ locale?: {
13
+ currentLanguageTag: string;
14
+ supported: { languageTag: string; url: string; label: string }[];
15
+ };
16
+ };
17
+
18
+ assert<KcContextBase extends KcContextLike ? true : false>();
19
+
20
+ export type MessageKeyBase = keyof typeof baseMessages | keyof (typeof keycloakifyExtraMessages)[typeof fallbackLanguageTag];
21
+
22
+ export type I18n<MessageKey extends string> = {
23
+ /**
24
+ * e.g: "en", "fr", "zh-CN"
25
+ *
26
+ * The current language
27
+ */
28
+ currentLanguageTag: string;
29
+ /**
30
+ * To call when the user switch language.
31
+ * This will cause the page to be reloaded,
32
+ * on next load currentLanguageTag === newLanguageTag
33
+ */
34
+ changeLocale: (newLanguageTag: string) => never;
35
+ /**
36
+ * e.g. "en" => "English", "fr" => "Français", ...
37
+ *
38
+ * Used to render a select that enable user to switch language.
39
+ * ex: https://user-images.githubusercontent.com/6702424/186044799-38801eec-4e89-483b-81dd-8e9233e8c0eb.png
40
+ * */
41
+ labelBySupportedLanguageTag: Record<string, string>;
42
+ /**
43
+ * Examples assuming currentLanguageTag === "en"
44
+ *
45
+ * msg("access-denied") === <span>Access denied</span>
46
+ * msg("impersonateTitleHtml", "Foo") === <span><strong>Foo</strong> Impersonate User</span>
47
+ */
48
+ msg: (key: MessageKey, ...args: (string | undefined)[]) => JSX.Element;
49
+ /**
50
+ * It's the same thing as msg() but instead of returning a JSX.Element it returns a string.
51
+ * It can be more convenient to manipulate strings but if there are HTML tags it wont render.
52
+ * msgStr("impersonateTitleHtml", "Foo") === "<strong>Foo</strong> Impersonate User"
53
+ */
54
+ msgStr: (key: MessageKey, ...args: (string | undefined)[]) => string;
55
+ /**
56
+ * Examples assuming currentLanguageTag === "en"
57
+ * advancedMsg("${access-denied} foo bar") === <span>${msgStr("access-denied")} foo bar<span> === <span>Access denied foo bar</span>
58
+ * advancedMsg("${access-denied}") === advancedMsg("access-denied") === msg("access-denied") === <span>Access denied</span>
59
+ * advancedMsg("${not-a-message-key}") === advancedMsg(not-a-message-key") === <span>not-a-message-key</span>
60
+ */
61
+ advancedMsg: (key: string, ...args: (string | undefined)[]) => JSX.Element;
62
+ /**
63
+ * Examples assuming currentLanguageTag === "en"
64
+ * advancedMsg("${access-denied} foo bar") === msg("access-denied") + " foo bar" === "Access denied foo bar"
65
+ * advancedMsg("${not-a-message-key}") === advancedMsg(not-a-message-key") === "not-a-message-key"
66
+ */
67
+ advancedMsgStr: (key: string, ...args: (string | undefined)[]) => string;
68
+ };
69
+
70
+ export type I18nBase = I18n<MessageKeyBase>;
71
+
72
+ export function __unsafe_useI18n<ExtraMessageKey extends string = never>(params: {
73
+ kcContext: KcContextLike;
74
+ extraMessages: { [languageTag: string]: { [key in ExtraMessageKey]: string } };
75
+ doSkip: boolean;
76
+ }): I18n<MessageKeyBase | ExtraMessageKey> | null {
77
+ const { kcContext, extraMessages, doSkip } = params;
78
+
79
+ const [i18n, setI18n] = useState<I18n<ExtraMessageKey | MessageKeyBase> | undefined>(undefined);
80
+
81
+ const refHasStartedFetching = useRef(false);
82
+
83
+ useEffect(() => {
84
+ if (doSkip || refHasStartedFetching.current) {
85
+ return;
86
+ }
87
+
88
+ refHasStartedFetching.current = true;
89
+
90
+ (async () => {
91
+ const { currentLanguageTag = fallbackLanguageTag } = kcContext.locale ?? {};
92
+
93
+ const [fallbackMessages, messages] = await Promise.all([
94
+ import("./generated_messages/18.0.1/login/en"),
95
+ (() => {
96
+ switch (currentLanguageTag) {
97
+ case "ca":
98
+ return import("./generated_messages/18.0.1/login/ca");
99
+ case "cs":
100
+ return import("./generated_messages/18.0.1/login/cs");
101
+ case "da":
102
+ return import("./generated_messages/18.0.1/login/da");
103
+ case "de":
104
+ return import("./generated_messages/18.0.1/login/de");
105
+ case "en":
106
+ return import("./generated_messages/18.0.1/login/en");
107
+ case "es":
108
+ return import("./generated_messages/18.0.1/login/es");
109
+ case "fi":
110
+ return import("./generated_messages/18.0.1/login/fi");
111
+ case "fr":
112
+ return import("./generated_messages/18.0.1/login/fr");
113
+ case "hu":
114
+ return import("./generated_messages/18.0.1/login/hu");
115
+ case "it":
116
+ return import("./generated_messages/18.0.1/login/it");
117
+ case "ja":
118
+ return import("./generated_messages/18.0.1/login/ja");
119
+ case "lt":
120
+ return import("./generated_messages/18.0.1/login/lt");
121
+ case "lv":
122
+ return import("./generated_messages/18.0.1/login/lv");
123
+ case "nl":
124
+ return import("./generated_messages/18.0.1/login/nl");
125
+ case "no":
126
+ return import("./generated_messages/18.0.1/login/no");
127
+ case "pl":
128
+ return import("./generated_messages/18.0.1/login/pl");
129
+ case "pt-BR":
130
+ return import("./generated_messages/18.0.1/login/pt-BR");
131
+ case "ru":
132
+ return import("./generated_messages/18.0.1/login/ru");
133
+ case "sk":
134
+ return import("./generated_messages/18.0.1/login/sk");
135
+ case "sv":
136
+ return import("./generated_messages/18.0.1/login/sv");
137
+ case "tr":
138
+ return import("./generated_messages/18.0.1/login/tr");
139
+ case "zh-CN":
140
+ return import("./generated_messages/18.0.1/login/zh-CN");
141
+ default:
142
+ return { "default": {} };
143
+ }
144
+ })()
145
+ ]).then(modules => modules.map(module => module.default));
146
+
147
+ setI18n({
148
+ ...createI18nTranslationFunctions({
149
+ "fallbackMessages": {
150
+ ...fallbackMessages,
151
+ ...(keycloakifyExtraMessages[fallbackLanguageTag] ?? {}),
152
+ ...(extraMessages[fallbackLanguageTag] ?? {})
153
+ } as any,
154
+ "messages": {
155
+ ...messages,
156
+ ...((keycloakifyExtraMessages as any)[currentLanguageTag] ?? {}),
157
+ ...(extraMessages[currentLanguageTag] ?? {})
158
+ } as any
159
+ }),
160
+ currentLanguageTag,
161
+ "changeLocale": newLanguageTag => {
162
+ const { locale } = kcContext;
163
+
164
+ assert(locale !== undefined, "Internationalization not enabled");
165
+
166
+ const targetSupportedLocale = locale.supported.find(({ languageTag }) => languageTag === newLanguageTag);
167
+
168
+ assert(targetSupportedLocale !== undefined, `${newLanguageTag} need to be enabled in Keycloak admin`);
169
+
170
+ window.location.href = targetSupportedLocale.url;
171
+
172
+ assert(false, "never");
173
+ },
174
+ "labelBySupportedLanguageTag": Object.fromEntries(
175
+ (kcContext.locale?.supported ?? []).map(({ languageTag, label }) => [languageTag, label])
176
+ )
177
+ });
178
+ })();
179
+ }, []);
180
+
181
+ return i18n ?? null;
182
+ }
183
+
184
+ const useI18n_private = __unsafe_useI18n;
185
+
186
+ export function useI18n<ExtraMessageKey extends string = never>(params: {
187
+ kcContext: KcContextLike;
188
+ extraMessages: { [languageTag: string]: { [key in ExtraMessageKey]: string } };
189
+ }): I18n<MessageKeyBase | ExtraMessageKey> | null {
190
+ return useI18n_private({
191
+ ...params,
192
+ "doSkip": false
193
+ });
194
+ }
195
+
196
+ function createI18nTranslationFunctions<MessageKey extends string>(params: {
197
+ fallbackMessages: Record<MessageKey, string>;
198
+ messages: Record<MessageKey, string>;
199
+ }): Pick<I18n<MessageKey>, "msg" | "msgStr" | "advancedMsg" | "advancedMsgStr"> {
200
+ const { fallbackMessages, messages } = params;
201
+
202
+ function resolveMsg(props: { key: string; args: (string | undefined)[]; doRenderMarkdown: boolean }): string | JSX.Element | undefined {
203
+ const { key, args, doRenderMarkdown } = props;
204
+
205
+ const messageOrUndefined: string | undefined = (messages as any)[key] ?? (fallbackMessages as any)[key];
206
+
207
+ if (messageOrUndefined === undefined) {
208
+ return undefined;
209
+ }
210
+
211
+ const message = messageOrUndefined;
212
+
213
+ const messageWithArgsInjectedIfAny = (() => {
214
+ const startIndex = message
215
+ .match(/{[0-9]+}/g)
216
+ ?.map(g => g.match(/{([0-9]+)}/)![1])
217
+ .map(indexStr => parseInt(indexStr))
218
+ .sort((a, b) => a - b)[0];
219
+
220
+ if (startIndex === undefined) {
221
+ // No {0} in message (no arguments expected)
222
+ return message;
223
+ }
224
+
225
+ let messageWithArgsInjected = message;
226
+
227
+ args.forEach((arg, i) => {
228
+ if (arg === undefined) {
229
+ return;
230
+ }
231
+
232
+ messageWithArgsInjected = messageWithArgsInjected.replace(new RegExp(`\\{${i + startIndex}\\}`, "g"), arg);
233
+ });
234
+
235
+ return messageWithArgsInjected;
236
+ })();
237
+
238
+ return doRenderMarkdown ? (
239
+ <Markdown allowDangerousHtml renderers={{ "paragraph": "span" }}>
240
+ {messageWithArgsInjectedIfAny}
241
+ </Markdown>
242
+ ) : (
243
+ messageWithArgsInjectedIfAny
244
+ );
245
+ }
246
+
247
+ function resolveMsgAdvanced(props: { key: string; args: (string | undefined)[]; doRenderMarkdown: boolean }): JSX.Element | string {
248
+ const { key, args, doRenderMarkdown } = props;
249
+
250
+ const match = key.match(/^\$\{([^{]+)\}$/);
251
+
252
+ const keyUnwrappedFromCurlyBraces = match === null ? key : match[1];
253
+
254
+ const out = resolveMsg({
255
+ "key": keyUnwrappedFromCurlyBraces,
256
+ args,
257
+ doRenderMarkdown
258
+ });
259
+
260
+ return (out !== undefined ? out : doRenderMarkdown ? <span>{keyUnwrappedFromCurlyBraces}</span> : keyUnwrappedFromCurlyBraces) as any;
261
+ }
262
+
263
+ return {
264
+ "msgStr": (key, ...args) => resolveMsg({ key, args, "doRenderMarkdown": false }) as string,
265
+ "msg": (key, ...args) => resolveMsg({ key, args, "doRenderMarkdown": true }) as JSX.Element,
266
+ "advancedMsg": (key, ...args) => resolveMsgAdvanced({ key, args, "doRenderMarkdown": true }) as JSX.Element,
267
+ "advancedMsgStr": (key, ...args) => resolveMsgAdvanced({ key, args, "doRenderMarkdown": false }) as string
268
+ };
269
+ }
270
+
271
+ const keycloakifyExtraMessages = {
272
+ "en": {
273
+ "shouldBeEqual": "{0} should be equal to {1}",
274
+ "shouldBeDifferent": "{0} should be different to {1}",
275
+ "shouldMatchPattern": "Pattern should match: `/{0}/`",
276
+ "mustBeAnInteger": "Must be an integer",
277
+ "notAValidOption": "Not a valid option"
278
+ },
279
+ "fr": {
280
+ /* spell-checker: disable */
281
+ "shouldBeEqual": "{0} doit être égal à {1}",
282
+ "shouldBeDifferent": "{0} doit être différent de {1}",
283
+ "shouldMatchPattern": "Dois respecter le schéma: `/{0}/`",
284
+ "mustBeAnInteger": "Doit être un nombre entier",
285
+ "notAValidOption": "N'est pas une option valide",
286
+
287
+ "logoutConfirmTitle": "Déconnexion",
288
+ "logoutConfirmHeader": "Êtes-vous sûr(e) de vouloir vous déconnecter ?",
289
+ "doLogout": "Se déconnecter"
290
+ /* spell-checker: enable */
291
+ }
292
+ };