keycloakify 10.0.0-rc.77 → 10.0.0-rc.78
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/account/i18n/i18n.d.ts +4 -4
- package/account/i18n/i18n.js +12 -34
- package/account/i18n/i18n.js.map +1 -1
- package/account/i18n/index.d.ts +1 -1
- package/account/i18n/index.js +1 -1
- package/account/i18n/index.js.map +1 -1
- package/account/i18n/useI18n.d.ts +13 -0
- package/account/i18n/useI18n.js +26 -0
- package/account/i18n/useI18n.js.map +1 -0
- package/bin/440.index.js +15 -19
- package/bin/751.index.js +0 -2
- package/bin/shared/constants.d.ts +0 -1
- package/bin/shared/constants.js +0 -1
- package/bin/shared/constants.js.map +1 -1
- package/login/KcContext/KcContext.d.ts +5 -1
- package/login/KcContext/KcContext.js +0 -1
- package/login/KcContext/KcContext.js.map +1 -1
- package/login/KcContext/kcContextMocks.js +4 -1
- package/login/KcContext/kcContextMocks.js.map +1 -1
- package/login/i18n/i18n.d.ts +7 -4
- package/login/i18n/i18n.js +23 -38
- package/login/i18n/i18n.js.map +1 -1
- package/login/i18n/index.d.ts +1 -1
- package/login/i18n/index.js +1 -1
- package/login/i18n/index.js.map +1 -1
- package/login/i18n/useI18n.d.ts +13 -0
- package/login/i18n/useI18n.js +26 -0
- package/login/i18n/useI18n.js.map +1 -0
- package/login/lib/useDownloadTerms.d.ts +5 -4
- package/login/lib/useDownloadTerms.js +26 -5
- package/login/lib/useDownloadTerms.js.map +1 -1
- package/login/pages/Register.js +7 -6
- package/login/pages/Register.js.map +1 -1
- package/login/pages/Terms.d.ts +1 -1
- package/login/pages/Terms.js +6 -4
- package/login/pages/Terms.js.map +1 -1
- package/package.json +15 -7
- package/src/account/i18n/i18n.tsx +19 -53
- package/src/account/i18n/index.ts +1 -1
- package/src/account/i18n/useI18n.ts +44 -0
- package/src/bin/keycloakify/generateFtl/generateFtl.ts +1 -6
- package/src/bin/keycloakify/generateFtl/kcContextDeclarationTemplate.ftl +8 -1
- package/src/bin/keycloakify/generateResources/generateMessageProperties.ts +23 -17
- package/src/bin/shared/constants.ts +0 -2
- package/src/login/KcContext/KcContext.ts +6 -14
- package/src/login/KcContext/kcContextMocks.ts +4 -1
- package/src/login/i18n/i18n.tsx +37 -58
- package/src/login/i18n/index.ts +1 -1
- package/src/login/i18n/useI18n.ts +44 -0
- package/src/login/lib/useDownloadTerms.tsx +88 -0
- package/src/login/pages/Register.tsx +12 -12
- package/src/login/pages/Terms.tsx +12 -11
- package/src/tools/react-markdown.ts +3 -0
- package/tools/react-markdown.d.ts +3 -0
- package/tools/react-markdown.js +4 -0
- package/tools/react-markdown.js.map +1 -0
- package/vite-plugin/index.js +0 -2
- package/src/login/lib/useDownloadTerms.ts +0 -57
- package/src/tools/Markdown.ts +0 -3
- package/tools/Markdown.d.ts +0 -2
- package/tools/Markdown.js +0 -3
- package/tools/Markdown.js.map +0 -1
package/login/pages/Terms.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"Terms.js","sourceRoot":"","sources":["../../src/login/pages/Terms.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,
|
1
|
+
{"version":3,"file":"Terms.js","sourceRoot":"","sources":["../../src/login/pages/Terms.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAK1E,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,KAAmE;IAC7F,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IAEtE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;QACzB,eAAe;QACf,OAAO;KACV,CAAC,CAAC;IAEH,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAE7B,MAAM,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC;IAE1B,OAAO,CACH,MAAC,QAAQ,kBACL,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,IAAI,EACV,eAAe,EAAE,eAAe,EAChC,OAAO,EAAE,OAAO,EAChB,cAAc,EAAE,KAAK,EACrB,UAAU,EAAE,GAAG,CAAC,YAAY,CAAC,iBAE7B,4BAAK,EAAE,EAAC,eAAe,gBAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAC,aAAa,KAAG,IAAO,EAC1F,8BAAM,SAAS,EAAC,cAAc,EAAC,MAAM,EAAE,GAAG,CAAC,WAAW,EAAE,MAAM,EAAC,MAAM,iBACjE,gBACI,SAAS,EAAE,MAAM,CAAC,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,sBAAsB,EAAE,oBAAoB,CAAC,EAClH,IAAI,EAAC,QAAQ,EACb,EAAE,EAAC,WAAW,EACd,IAAI,EAAC,QAAQ,EACb,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,GAC3B,EACF,gBACI,SAAS,EAAE,MAAM,CAAC,eAAe,EAAE,sBAAsB,EAAE,oBAAoB,CAAC,EAChF,IAAI,EAAC,QAAQ,EACb,EAAE,EAAC,YAAY,EACf,IAAI,EAAC,QAAQ,EACb,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,GAC5B,KACC,EACP,cAAK,SAAS,EAAC,UAAU,GAAG,KACrB,CACd,CAAC;AACN,CAAC;AAED,SAAS,aAAa;IAClB,MAAM,EAAE,kBAAkB,EAAE,aAAa,EAAE,aAAa,EAAE,GAAG,gBAAgB,EAAE,CAAC;IAEhF,IAAI,CAAC,kBAAkB,EAAE;QACrB,OAAO,IAAI,CAAC;KACf;IAED,OAAO,KAAC,aAAa,cAAE,aAAa,GAAiB,CAAC;AAC1D,CAAC"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "keycloakify",
|
3
|
-
"version": "10.0.0-rc.
|
3
|
+
"version": "10.0.0-rc.78",
|
4
4
|
"description": "Create Keycloak themes using React",
|
5
5
|
"repository": {
|
6
6
|
"type": "git",
|
@@ -136,6 +136,9 @@
|
|
136
136
|
"account/i18n/index.d.ts",
|
137
137
|
"account/i18n/index.js",
|
138
138
|
"account/i18n/index.js.map",
|
139
|
+
"account/i18n/useI18n.d.ts",
|
140
|
+
"account/i18n/useI18n.js",
|
141
|
+
"account/i18n/useI18n.js.map",
|
139
142
|
"account/index.d.ts",
|
140
143
|
"account/index.js",
|
141
144
|
"account/index.js.map",
|
@@ -289,6 +292,9 @@
|
|
289
292
|
"login/i18n/index.d.ts",
|
290
293
|
"login/i18n/index.js",
|
291
294
|
"login/i18n/index.js.map",
|
295
|
+
"login/i18n/useI18n.d.ts",
|
296
|
+
"login/i18n/useI18n.js",
|
297
|
+
"login/i18n/useI18n.js.map",
|
292
298
|
"login/index.d.ts",
|
293
299
|
"login/index.js",
|
294
300
|
"login/index.js.map",
|
@@ -444,6 +450,7 @@
|
|
444
450
|
"src/account/i18n/baseMessages/zh-CN.ts",
|
445
451
|
"src/account/i18n/i18n.tsx",
|
446
452
|
"src/account/i18n/index.ts",
|
453
|
+
"src/account/i18n/useI18n.ts",
|
447
454
|
"src/account/index.ts",
|
448
455
|
"src/account/lib/kcClsx.ts",
|
449
456
|
"src/account/pages/Account.tsx",
|
@@ -572,9 +579,10 @@
|
|
572
579
|
"src/login/i18n/baseMessages/zh-CN.ts",
|
573
580
|
"src/login/i18n/i18n.tsx",
|
574
581
|
"src/login/i18n/index.ts",
|
582
|
+
"src/login/i18n/useI18n.ts",
|
575
583
|
"src/login/index.ts",
|
576
584
|
"src/login/lib/kcClsx.ts",
|
577
|
-
"src/login/lib/useDownloadTerms.
|
585
|
+
"src/login/lib/useDownloadTerms.tsx",
|
578
586
|
"src/login/lib/useUserProfileForm.tsx",
|
579
587
|
"src/login/pages/Code.tsx",
|
580
588
|
"src/login/pages/DeleteAccountConfirm.tsx",
|
@@ -616,7 +624,6 @@
|
|
616
624
|
"src/tools/ExtractAfterStartingWith.ts",
|
617
625
|
"src/tools/HTMLElement.prototype.prepend.ts",
|
618
626
|
"src/tools/LazyOrNot.ts",
|
619
|
-
"src/tools/Markdown.ts",
|
620
627
|
"src/tools/Object.fromEntries.ts",
|
621
628
|
"src/tools/StatefulObservable/README.md",
|
622
629
|
"src/tools/StatefulObservable/StatefulObservable.ts",
|
@@ -632,6 +639,7 @@
|
|
632
639
|
"src/tools/emailRegExp.ts",
|
633
640
|
"src/tools/formatNumber.ts",
|
634
641
|
"src/tools/pathBasename.ts",
|
642
|
+
"src/tools/react-markdown.ts",
|
635
643
|
"src/tools/structuredCloneButFunctions.ts",
|
636
644
|
"src/tools/useConst.ts",
|
637
645
|
"src/tools/useConstCallback.ts",
|
@@ -699,9 +707,6 @@
|
|
699
707
|
"tools/LazyOrNot.d.ts",
|
700
708
|
"tools/LazyOrNot.js",
|
701
709
|
"tools/LazyOrNot.js.map",
|
702
|
-
"tools/Markdown.d.ts",
|
703
|
-
"tools/Markdown.js",
|
704
|
-
"tools/Markdown.js.map",
|
705
710
|
"tools/Object.fromEntries.d.ts",
|
706
711
|
"tools/Object.fromEntries.js",
|
707
712
|
"tools/Object.fromEntries.js.map",
|
@@ -744,6 +749,9 @@
|
|
744
749
|
"tools/pathBasename.d.ts",
|
745
750
|
"tools/pathBasename.js",
|
746
751
|
"tools/pathBasename.js.map",
|
752
|
+
"tools/react-markdown.d.ts",
|
753
|
+
"tools/react-markdown.js",
|
754
|
+
"tools/react-markdown.js.map",
|
747
755
|
"tools/structuredCloneButFunctions.d.ts",
|
748
756
|
"tools/structuredCloneButFunctions.js",
|
749
757
|
"tools/structuredCloneButFunctions.js.map",
|
@@ -824,7 +832,7 @@
|
|
824
832
|
"react": "*"
|
825
833
|
},
|
826
834
|
"dependencies": {
|
827
|
-
"react-markdown": "^
|
835
|
+
"react-markdown": "^9.0.1",
|
828
836
|
"tsafe": "^1.6.6"
|
829
837
|
},
|
830
838
|
"devDependencies": {
|
@@ -1,10 +1,8 @@
|
|
1
1
|
import "keycloakify/tools/Object.fromEntries";
|
2
|
-
import { useEffect, useState } from "react";
|
3
2
|
import { assert } from "tsafe/assert";
|
4
3
|
import messages_fallbackLanguage from "./baseMessages/en";
|
5
4
|
import { getMessages } from "./baseMessages";
|
6
5
|
import type { KcContext } from "../KcContext";
|
7
|
-
import { Reflect } from "tsafe/Reflect";
|
8
6
|
|
9
7
|
export const fallbackLanguageTag = "en";
|
10
8
|
|
@@ -88,7 +86,9 @@ export type GenericI18n<MessageKey extends string> = {
|
|
88
86
|
isFetchingTranslations: boolean;
|
89
87
|
};
|
90
88
|
|
91
|
-
function createGetI18n<ExtraMessageKey extends string = never>(
|
89
|
+
export function createGetI18n<ExtraMessageKey extends string = never>(messageBundle: {
|
90
|
+
[languageTag: string]: { [key in ExtraMessageKey]: string };
|
91
|
+
}) {
|
92
92
|
type I18n = GenericI18n<MessageKey | ExtraMessageKey>;
|
93
93
|
|
94
94
|
type Result = { i18n: I18n; prI18n_currentLanguage: Promise<I18n> | undefined };
|
@@ -126,8 +126,8 @@ function createGetI18n<ExtraMessageKey extends string = never>(extraMessages: {
|
|
126
126
|
|
127
127
|
const { createI18nTranslationFunctions } = createI18nTranslationFunctionsFactory<MessageKey, ExtraMessageKey>({
|
128
128
|
messages_fallbackLanguage,
|
129
|
-
|
130
|
-
|
129
|
+
messageBundle_fallbackLanguage: messageBundle[fallbackLanguageTag],
|
130
|
+
messageBundle_currentLanguage: messageBundle[partialI18n.currentLanguageTag]
|
131
131
|
});
|
132
132
|
|
133
133
|
const isCurrentLanguageFallbackLanguage = partialI18n.currentLanguageTag === fallbackLanguageTag;
|
@@ -135,17 +135,19 @@ function createGetI18n<ExtraMessageKey extends string = never>(extraMessages: {
|
|
135
135
|
const result: Result = {
|
136
136
|
i18n: {
|
137
137
|
...partialI18n,
|
138
|
-
...createI18nTranslationFunctions({
|
138
|
+
...createI18nTranslationFunctions({
|
139
|
+
messages_currentLanguage: isCurrentLanguageFallbackLanguage ? messages_fallbackLanguage : undefined
|
140
|
+
}),
|
139
141
|
isFetchingTranslations: !isCurrentLanguageFallbackLanguage
|
140
142
|
},
|
141
143
|
prI18n_currentLanguage: isCurrentLanguageFallbackLanguage
|
142
144
|
? undefined
|
143
145
|
: (async () => {
|
144
|
-
const
|
146
|
+
const messages_currentLanguage = await getMessages(partialI18n.currentLanguageTag);
|
145
147
|
|
146
148
|
const i18n_currentLanguage: I18n = {
|
147
149
|
...partialI18n,
|
148
|
-
...createI18nTranslationFunctions({
|
150
|
+
...createI18nTranslationFunctions({ messages_currentLanguage }),
|
149
151
|
isFetchingTranslations: false
|
150
152
|
};
|
151
153
|
|
@@ -168,66 +170,30 @@ function createGetI18n<ExtraMessageKey extends string = never>(extraMessages: {
|
|
168
170
|
return { getI18n };
|
169
171
|
}
|
170
172
|
|
171
|
-
export function createUseI18n<ExtraMessageKey extends string = never>(extraMessages: {
|
172
|
-
[languageTag: string]: { [key in ExtraMessageKey]: string };
|
173
|
-
}) {
|
174
|
-
type I18n = GenericI18n<MessageKey | ExtraMessageKey>;
|
175
|
-
|
176
|
-
const { getI18n } = createGetI18n(extraMessages);
|
177
|
-
|
178
|
-
function useI18n(params: { kcContext: KcContextLike }): { i18n: I18n } {
|
179
|
-
const { kcContext } = params;
|
180
|
-
|
181
|
-
const { i18n, prI18n_currentLanguage } = getI18n({ kcContext });
|
182
|
-
|
183
|
-
const [i18n_toReturn, setI18n_toReturn] = useState<I18n>(i18n);
|
184
|
-
|
185
|
-
useEffect(() => {
|
186
|
-
let isActive = true;
|
187
|
-
|
188
|
-
prI18n_currentLanguage?.then(i18n => {
|
189
|
-
if (!isActive) {
|
190
|
-
return;
|
191
|
-
}
|
192
|
-
|
193
|
-
setI18n_toReturn(i18n);
|
194
|
-
});
|
195
|
-
|
196
|
-
return () => {
|
197
|
-
isActive = false;
|
198
|
-
};
|
199
|
-
}, []);
|
200
|
-
|
201
|
-
return { i18n: i18n_toReturn };
|
202
|
-
}
|
203
|
-
|
204
|
-
return { useI18n, ofTypeI18n: Reflect<I18n>() };
|
205
|
-
}
|
206
|
-
|
207
173
|
function createI18nTranslationFunctionsFactory<MessageKey extends string, ExtraMessageKey extends string>(params: {
|
208
174
|
messages_fallbackLanguage: Record<MessageKey, string>;
|
209
|
-
|
210
|
-
|
175
|
+
messageBundle_fallbackLanguage: Record<ExtraMessageKey, string> | undefined;
|
176
|
+
messageBundle_currentLanguage: Partial<Record<ExtraMessageKey, string>> | undefined;
|
211
177
|
}) {
|
212
|
-
const {
|
178
|
+
const { messageBundle_currentLanguage } = params;
|
213
179
|
|
214
180
|
const messages_fallbackLanguage = {
|
215
181
|
...params.messages_fallbackLanguage,
|
216
|
-
...params.
|
182
|
+
...params.messageBundle_fallbackLanguage
|
217
183
|
};
|
218
184
|
|
219
185
|
function createI18nTranslationFunctions(params: {
|
220
|
-
|
186
|
+
messages_currentLanguage: Partial<Record<MessageKey, string>> | undefined;
|
221
187
|
}): Pick<GenericI18n<MessageKey | ExtraMessageKey>, "msg" | "msgStr" | "advancedMsg" | "advancedMsgStr"> {
|
222
|
-
const
|
223
|
-
...params.
|
224
|
-
...
|
188
|
+
const messages_currentLanguage = {
|
189
|
+
...params.messages_currentLanguage,
|
190
|
+
...messageBundle_currentLanguage
|
225
191
|
};
|
226
192
|
|
227
193
|
function resolveMsg(props: { key: string; args: (string | undefined)[]; doRenderAsHtml: boolean }): string | JSX.Element | undefined {
|
228
194
|
const { key, args, doRenderAsHtml } = props;
|
229
195
|
|
230
|
-
const messageOrUndefined: string | undefined = (
|
196
|
+
const messageOrUndefined: string | undefined = (messages_currentLanguage as any)[key] ?? (messages_fallbackLanguage as any)[key];
|
231
197
|
|
232
198
|
if (messageOrUndefined === undefined) {
|
233
199
|
return undefined;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import type { GenericI18n, MessageKey, KcContextLike } from "./i18n";
|
2
2
|
export type { MessageKey, KcContextLike };
|
3
3
|
export type I18n = GenericI18n<MessageKey>;
|
4
|
-
export { createUseI18n } from "./
|
4
|
+
export { createUseI18n } from "./useI18n";
|
5
5
|
export { fallbackLanguageTag } from "./i18n";
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import { useEffect, useState } from "react";
|
2
|
+
import {
|
3
|
+
createGetI18n,
|
4
|
+
type GenericI18n,
|
5
|
+
type MessageKey,
|
6
|
+
type KcContextLike
|
7
|
+
} from "./i18n";
|
8
|
+
import { Reflect } from "tsafe/Reflect";
|
9
|
+
|
10
|
+
export function createUseI18n<ExtraMessageKey extends string = never>(extraMessages: {
|
11
|
+
[languageTag: string]: { [key in ExtraMessageKey]: string };
|
12
|
+
}) {
|
13
|
+
type I18n = GenericI18n<MessageKey | ExtraMessageKey>;
|
14
|
+
|
15
|
+
const { getI18n } = createGetI18n(extraMessages);
|
16
|
+
|
17
|
+
function useI18n(params: { kcContext: KcContextLike }): { i18n: I18n } {
|
18
|
+
const { kcContext } = params;
|
19
|
+
|
20
|
+
const { i18n, prI18n_currentLanguage } = getI18n({ kcContext });
|
21
|
+
|
22
|
+
const [i18n_toReturn, setI18n_toReturn] = useState<I18n>(i18n);
|
23
|
+
|
24
|
+
useEffect(() => {
|
25
|
+
let isActive = true;
|
26
|
+
|
27
|
+
prI18n_currentLanguage?.then(i18n => {
|
28
|
+
if (!isActive) {
|
29
|
+
return;
|
30
|
+
}
|
31
|
+
|
32
|
+
setI18n_toReturn(i18n);
|
33
|
+
});
|
34
|
+
|
35
|
+
return () => {
|
36
|
+
isActive = false;
|
37
|
+
};
|
38
|
+
}, []);
|
39
|
+
|
40
|
+
return { i18n: i18n_toReturn };
|
41
|
+
}
|
42
|
+
|
43
|
+
return { useI18n, ofTypeI18n: Reflect<I18n>() };
|
44
|
+
}
|
@@ -8,8 +8,7 @@ import { assert } from "tsafe/assert";
|
|
8
8
|
import {
|
9
9
|
type ThemeType,
|
10
10
|
basenameOfTheKeycloakifyResourcesDir,
|
11
|
-
resources_common
|
12
|
-
nameOfTheLocalizationRealmOverridesUserProfileProperty
|
11
|
+
resources_common
|
13
12
|
} from "../../shared/constants";
|
14
13
|
import { getThisCodebaseRootDirPath } from "../../tools/getThisCodebaseRootDirPath";
|
15
14
|
|
@@ -119,10 +118,6 @@ export function generateFtlFilesCodeFactory(params: {
|
|
119
118
|
.replace("KEYCLOAKIFY_THEME_TYPE_dExKd3xEdr", themeType)
|
120
119
|
.replace("KEYCLOAKIFY_THEME_NAME_cXxKd3xEer", themeName)
|
121
120
|
.replace("RESOURCES_COMMON_cLsLsMrtDkpVv", resources_common)
|
122
|
-
.replace(
|
123
|
-
"lOCALIZATION_REALM_OVERRIDES_USER_PROFILE_PROPERTY_KEY_aaGLsPgGIdeeX",
|
124
|
-
nameOfTheLocalizationRealmOverridesUserProfileProperty
|
125
|
-
)
|
126
121
|
.replace(
|
127
122
|
"USER_DEFINED_EXCLUSIONS_eKsaY4ZsZ4eMr2",
|
128
123
|
buildContext.kcContextExclusionsFtlCode ?? ""
|
@@ -33,8 +33,9 @@ kcContext.pageId = "${pageId}";
|
|
33
33
|
if( kcContext.url && kcContext.url.resourcesPath ){
|
34
34
|
kcContext.url.resourcesCommonPath = kcContext.url.resourcesPath + "/" + "RESOURCES_COMMON_cLsLsMrtDkpVv";
|
35
35
|
}
|
36
|
+
kcContext["x-keycloakify"] = {};
|
36
37
|
<#if profile?? && profile.attributes??>
|
37
|
-
kcContext.
|
38
|
+
kcContext["x-keycloakify"].realmMessageBundleUserProfile = {
|
38
39
|
<#list profile.attributes as attribute>
|
39
40
|
<#if attribute.annotations?? && attribute.displayName??>
|
40
41
|
"${attribute.displayName}": decodeHtmlEntities("${advancedMsg(attribute.displayName)?js_string}"),
|
@@ -61,6 +62,9 @@ if( kcContext.url && kcContext.url.resourcesPath ){
|
|
61
62
|
</#list>
|
62
63
|
};
|
63
64
|
</#if>
|
65
|
+
<#if pageId == "terms.ftl" || termsAcceptanceRequired?? && termsAcceptanceRequired>
|
66
|
+
kcContext["x-keycloakify"].realmMessageBundleTermsText= decodeHtmlEntities("${msg("termsText")?js_string}");
|
67
|
+
</#if>
|
64
68
|
attributes_to_attributesByName: {
|
65
69
|
if( !kcContext.profile ){
|
66
70
|
break attributes_to_attributesByName;
|
@@ -198,6 +202,9 @@ function decodeHtmlEntities(htmlStr){
|
|
198
202
|
) || (
|
199
203
|
key == "execution" &&
|
200
204
|
are_same_path(path, [])
|
205
|
+
) || (
|
206
|
+
key == "entity" &&
|
207
|
+
are_same_path(path, ["user"])
|
201
208
|
)
|
202
209
|
>
|
203
210
|
<#-- <#local out_seq += ["/*" + path?join(".") + "." + key + " excluded*/"]> -->
|
@@ -9,6 +9,8 @@ import * as babelParser from "@babel/parser";
|
|
9
9
|
import babelGenerate from "@babel/generator";
|
10
10
|
import * as babelTypes from "@babel/types";
|
11
11
|
import { escapeStringForPropertiesFile } from "../../tools/escapeStringForPropertiesFile";
|
12
|
+
import { getThisCodebaseRootDirPath } from "../../tools/getThisCodebaseRootDirPath";
|
13
|
+
import * as fs from "fs";
|
12
14
|
|
13
15
|
export function generateMessageProperties(params: {
|
14
16
|
themeSrcDirPath: string;
|
@@ -39,10 +41,6 @@ export function generateMessageProperties(params: {
|
|
39
41
|
readFileSync(file).toString("utf8").includes("createUseI18n")
|
40
42
|
);
|
41
43
|
|
42
|
-
if (files.length === 0) {
|
43
|
-
return [];
|
44
|
-
}
|
45
|
-
|
46
44
|
const extraMessages = files
|
47
45
|
.map(file => {
|
48
46
|
const root = recast.parse(readFileSync(file).toString("utf8"), {
|
@@ -99,15 +97,28 @@ export function generateMessageProperties(params: {
|
|
99
97
|
return extraMessages;
|
100
98
|
});
|
101
99
|
|
102
|
-
const languageTags =
|
103
|
-
.map(extraMessage => Object.keys(extraMessage))
|
104
|
-
|
105
|
-
|
100
|
+
const languageTags = [
|
101
|
+
...extraMessages.map(extraMessage => Object.keys(extraMessage)).flat(),
|
102
|
+
...fs
|
103
|
+
.readdirSync(
|
104
|
+
pathJoin(
|
105
|
+
getThisCodebaseRootDirPath(),
|
106
|
+
"src",
|
107
|
+
themeType,
|
108
|
+
"i18n",
|
109
|
+
"baseMessages"
|
110
|
+
)
|
111
|
+
)
|
112
|
+
.filter(baseName => baseName !== "index.ts")
|
113
|
+
.map(baseName => baseName.replace(/\.ts$/, ""))
|
114
|
+
].reduce(...removeDuplicates<string>());
|
106
115
|
|
107
116
|
const keyValueMapByLanguageTag: Record<string, Record<string, string>> = {};
|
108
117
|
|
109
118
|
for (const languageTag of languageTags) {
|
110
|
-
const keyValueMap: Record<string, string> = {
|
119
|
+
const keyValueMap: Record<string, string> = {
|
120
|
+
termsText: ""
|
121
|
+
};
|
111
122
|
|
112
123
|
for (const extraMessage of extraMessages) {
|
113
124
|
const keyValueMap_i = extraMessage[languageTag];
|
@@ -152,14 +163,9 @@ export function generateMessageProperties(params: {
|
|
152
163
|
|
153
164
|
out.push({
|
154
165
|
languageTag,
|
155
|
-
propertiesFileSource: [
|
156
|
-
"
|
157
|
-
|
158
|
-
"parent=base",
|
159
|
-
"",
|
160
|
-
propertiesFileSource,
|
161
|
-
""
|
162
|
-
].join("\n")
|
166
|
+
propertiesFileSource: ["", "parent=base", "", propertiesFileSource, ""].join(
|
167
|
+
"\n"
|
168
|
+
)
|
163
169
|
});
|
164
170
|
}
|
165
171
|
|
@@ -1,5 +1,3 @@
|
|
1
|
-
export const nameOfTheLocalizationRealmOverridesUserProfileProperty =
|
2
|
-
"__localizationRealmOverridesUserProfile";
|
3
1
|
export const keycloak_resources = "keycloak-resources";
|
4
2
|
export const resources_common = "resources-common";
|
5
3
|
export const lastKeycloakVersionWithAccountV1 = "21.1.2";
|
@@ -1,8 +1,4 @@
|
|
1
|
-
import type {
|
2
|
-
ThemeType,
|
3
|
-
LoginThemePageId,
|
4
|
-
nameOfTheLocalizationRealmOverridesUserProfileProperty
|
5
|
-
} from "keycloakify/bin/shared/constants";
|
1
|
+
import type { ThemeType, LoginThemePageId } from "keycloakify/bin/shared/constants";
|
6
2
|
import type { ExtractAfterStartingWith } from "keycloakify/tools/ExtractAfterStartingWith";
|
7
3
|
import type { ValueOf } from "keycloakify/tools/ValueOf";
|
8
4
|
import { assert } from "tsafe/assert";
|
@@ -158,7 +154,10 @@ export declare namespace KcContext {
|
|
158
154
|
ssoLoginInOtherTabsUrl: string;
|
159
155
|
};
|
160
156
|
properties: {};
|
161
|
-
|
157
|
+
"x-keycloakify": {
|
158
|
+
realmMessageBundleUserProfile: Record<string, string> | undefined;
|
159
|
+
realmMessageBundleTermsText: string | undefined;
|
160
|
+
};
|
162
161
|
};
|
163
162
|
|
164
163
|
export type SamlPostForm = Common & {
|
@@ -276,6 +275,7 @@ export declare namespace KcContext {
|
|
276
275
|
lastName?: string;
|
277
276
|
markedForEviction?: boolean;
|
278
277
|
};
|
278
|
+
__localizationRealmOverridesTermsText?: string;
|
279
279
|
};
|
280
280
|
|
281
281
|
export type LoginDeviceVerifyUserCode = Common & {
|
@@ -772,11 +772,3 @@ export type PasswordPolicies = {
|
|
772
772
|
/** Whether the password can be the email address */
|
773
773
|
notEmail?: boolean;
|
774
774
|
};
|
775
|
-
|
776
|
-
assert<
|
777
|
-
KcContext.Common extends Partial<
|
778
|
-
Record<typeof nameOfTheLocalizationRealmOverridesUserProfileProperty, unknown>
|
779
|
-
>
|
780
|
-
? true
|
781
|
-
: false
|
782
|
-
>();
|
@@ -161,7 +161,10 @@ export const kcContextCommonMock: KcContext.Common = {
|
|
161
161
|
scripts: [],
|
162
162
|
isAppInitiatedAction: false,
|
163
163
|
properties: {},
|
164
|
-
|
164
|
+
"x-keycloakify": {
|
165
|
+
realmMessageBundleUserProfile: undefined,
|
166
|
+
realmMessageBundleTermsText: undefined
|
167
|
+
}
|
165
168
|
};
|
166
169
|
|
167
170
|
const loginUrl = {
|
package/src/login/i18n/i18n.tsx
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
import "keycloakify/tools/Object.fromEntries";
|
2
|
-
import { useEffect, useState } from "react";
|
3
2
|
import { assert } from "tsafe/assert";
|
4
3
|
import messages_fallbackLanguage from "./baseMessages/en";
|
5
4
|
import { getMessages } from "./baseMessages";
|
6
5
|
import type { KcContext } from "../KcContext";
|
7
|
-
import { Reflect } from "tsafe/Reflect";
|
8
6
|
|
9
7
|
export const fallbackLanguageTag = "en";
|
10
8
|
|
@@ -13,7 +11,10 @@ export type KcContextLike = {
|
|
13
11
|
currentLanguageTag: string;
|
14
12
|
supported: { languageTag: string; url: string; label: string }[];
|
15
13
|
};
|
16
|
-
|
14
|
+
"x-keycloakify": {
|
15
|
+
realmMessageBundleUserProfile: Record<string, string> | undefined;
|
16
|
+
realmMessageBundleTermsText: string | undefined;
|
17
|
+
};
|
17
18
|
};
|
18
19
|
|
19
20
|
assert<KcContext extends KcContextLike ? true : false>();
|
@@ -89,7 +90,9 @@ export type GenericI18n<MessageKey extends string> = {
|
|
89
90
|
isFetchingTranslations: boolean;
|
90
91
|
};
|
91
92
|
|
92
|
-
function createGetI18n<ExtraMessageKey extends string = never>(
|
93
|
+
export function createGetI18n<ExtraMessageKey extends string = never>(messageBundle: {
|
94
|
+
[languageTag: string]: { [key in ExtraMessageKey]: string };
|
95
|
+
}) {
|
93
96
|
type I18n = GenericI18n<MessageKey | ExtraMessageKey>;
|
94
97
|
|
95
98
|
type Result = { i18n: I18n; prI18n_currentLanguage: Promise<I18n> | undefined };
|
@@ -127,9 +130,10 @@ function createGetI18n<ExtraMessageKey extends string = never>(extraMessages: {
|
|
127
130
|
|
128
131
|
const { createI18nTranslationFunctions } = createI18nTranslationFunctionsFactory<MessageKey, ExtraMessageKey>({
|
129
132
|
messages_fallbackLanguage,
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
+
messageBundle_fallbackLanguage: messageBundle[fallbackLanguageTag],
|
134
|
+
messageBundle_currentLanguage: messageBundle[partialI18n.currentLanguageTag],
|
135
|
+
realmMessageBundleUserProfile: kcContext["x-keycloakify"].realmMessageBundleUserProfile,
|
136
|
+
realmMessageBundleTermsText: kcContext["x-keycloakify"].realmMessageBundleTermsText
|
133
137
|
});
|
134
138
|
|
135
139
|
const isCurrentLanguageFallbackLanguage = partialI18n.currentLanguageTag === fallbackLanguageTag;
|
@@ -137,17 +141,19 @@ function createGetI18n<ExtraMessageKey extends string = never>(extraMessages: {
|
|
137
141
|
const result: Result = {
|
138
142
|
i18n: {
|
139
143
|
...partialI18n,
|
140
|
-
...createI18nTranslationFunctions({
|
144
|
+
...createI18nTranslationFunctions({
|
145
|
+
messages_currentLanguage: isCurrentLanguageFallbackLanguage ? messages_fallbackLanguage : undefined
|
146
|
+
}),
|
141
147
|
isFetchingTranslations: !isCurrentLanguageFallbackLanguage
|
142
148
|
},
|
143
149
|
prI18n_currentLanguage: isCurrentLanguageFallbackLanguage
|
144
150
|
? undefined
|
145
151
|
: (async () => {
|
146
|
-
const
|
152
|
+
const messages_currentLanguage = await getMessages(partialI18n.currentLanguageTag);
|
147
153
|
|
148
154
|
const i18n_currentLanguage: I18n = {
|
149
155
|
...partialI18n,
|
150
|
-
...createI18nTranslationFunctions({
|
156
|
+
...createI18nTranslationFunctions({ messages_currentLanguage }),
|
151
157
|
isFetchingTranslations: false
|
152
158
|
};
|
153
159
|
|
@@ -170,67 +176,40 @@ function createGetI18n<ExtraMessageKey extends string = never>(extraMessages: {
|
|
170
176
|
return { getI18n };
|
171
177
|
}
|
172
178
|
|
173
|
-
export function createUseI18n<ExtraMessageKey extends string = never>(extraMessages: {
|
174
|
-
[languageTag: string]: { [key in ExtraMessageKey]: string };
|
175
|
-
}) {
|
176
|
-
type I18n = GenericI18n<MessageKey | ExtraMessageKey>;
|
177
|
-
|
178
|
-
const { getI18n } = createGetI18n(extraMessages);
|
179
|
-
|
180
|
-
function useI18n(params: { kcContext: KcContextLike }): { i18n: I18n } {
|
181
|
-
const { kcContext } = params;
|
182
|
-
|
183
|
-
const { i18n, prI18n_currentLanguage } = getI18n({ kcContext });
|
184
|
-
|
185
|
-
const [i18n_toReturn, setI18n_toReturn] = useState<I18n>(i18n);
|
186
|
-
|
187
|
-
useEffect(() => {
|
188
|
-
let isActive = true;
|
189
|
-
|
190
|
-
prI18n_currentLanguage?.then(i18n => {
|
191
|
-
if (!isActive) {
|
192
|
-
return;
|
193
|
-
}
|
194
|
-
|
195
|
-
setI18n_toReturn(i18n);
|
196
|
-
});
|
197
|
-
|
198
|
-
return () => {
|
199
|
-
isActive = false;
|
200
|
-
};
|
201
|
-
}, []);
|
202
|
-
|
203
|
-
return { i18n: i18n_toReturn };
|
204
|
-
}
|
205
|
-
|
206
|
-
return { useI18n, ofTypeI18n: Reflect<I18n>() };
|
207
|
-
}
|
208
|
-
|
209
179
|
function createI18nTranslationFunctionsFactory<MessageKey extends string, ExtraMessageKey extends string>(params: {
|
210
180
|
messages_fallbackLanguage: Record<MessageKey, string>;
|
211
|
-
|
212
|
-
|
213
|
-
|
181
|
+
messageBundle_fallbackLanguage: Record<ExtraMessageKey, string> | undefined;
|
182
|
+
messageBundle_currentLanguage: Partial<Record<ExtraMessageKey, string>> | undefined;
|
183
|
+
realmMessageBundleUserProfile: Record<string, string> | undefined;
|
184
|
+
realmMessageBundleTermsText: string | undefined;
|
214
185
|
}) {
|
215
|
-
const {
|
186
|
+
const { messageBundle_currentLanguage, realmMessageBundleUserProfile, realmMessageBundleTermsText } = params;
|
216
187
|
|
217
188
|
const messages_fallbackLanguage = {
|
218
189
|
...params.messages_fallbackLanguage,
|
219
|
-
...params.
|
190
|
+
...params.messageBundle_fallbackLanguage
|
220
191
|
};
|
221
192
|
|
222
193
|
function createI18nTranslationFunctions(params: {
|
223
|
-
|
194
|
+
messages_currentLanguage: Partial<Record<MessageKey, string>> | undefined;
|
224
195
|
}): Pick<GenericI18n<MessageKey | ExtraMessageKey>, "msg" | "msgStr" | "advancedMsg" | "advancedMsgStr"> {
|
225
|
-
const
|
226
|
-
...params.
|
227
|
-
...
|
196
|
+
const messages_currentLanguage = {
|
197
|
+
...params.messages_currentLanguage,
|
198
|
+
...messageBundle_currentLanguage
|
228
199
|
};
|
229
200
|
|
230
201
|
function resolveMsg(props: { key: string; args: (string | undefined)[]; doRenderAsHtml: boolean }): string | JSX.Element | undefined {
|
231
202
|
const { key, args, doRenderAsHtml } = props;
|
232
203
|
|
233
|
-
const messageOrUndefined: string | undefined = (
|
204
|
+
const messageOrUndefined: string | undefined = (() => {
|
205
|
+
const messageOrUndefined = (messages_currentLanguage as any)[key] ?? (messages_fallbackLanguage as any)[key];
|
206
|
+
|
207
|
+
if (key === "termsText") {
|
208
|
+
return realmMessageBundleTermsText;
|
209
|
+
}
|
210
|
+
|
211
|
+
return messageOrUndefined;
|
212
|
+
})();
|
234
213
|
|
235
214
|
if (messageOrUndefined === undefined) {
|
236
215
|
return undefined;
|
@@ -281,8 +260,8 @@ function createI18nTranslationFunctionsFactory<MessageKey extends string, ExtraM
|
|
281
260
|
function resolveMsgAdvanced(props: { key: string; args: (string | undefined)[]; doRenderAsHtml: boolean }): JSX.Element | string {
|
282
261
|
const { key, args, doRenderAsHtml } = props;
|
283
262
|
|
284
|
-
if (
|
285
|
-
const resolvedMessage =
|
263
|
+
if (realmMessageBundleUserProfile !== undefined && key in realmMessageBundleUserProfile) {
|
264
|
+
const resolvedMessage = realmMessageBundleUserProfile[key];
|
286
265
|
|
287
266
|
return doRenderAsHtml ? (
|
288
267
|
<span
|
package/src/login/i18n/index.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import type { GenericI18n, MessageKey, KcContextLike } from "./i18n";
|
2
2
|
export type { MessageKey, KcContextLike };
|
3
3
|
export type I18n = GenericI18n<MessageKey>;
|
4
|
-
export { createUseI18n } from "./
|
4
|
+
export { createUseI18n } from "./useI18n";
|
5
5
|
export { fallbackLanguageTag } from "./i18n";
|