keycloakify 10.1.3 → 11.0.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.
- package/account/KcContext/kcContextMocks.js +18 -6
- package/account/KcContext/kcContextMocks.js.map +1 -1
- package/account/Template.js +8 -26
- package/account/Template.js.map +1 -1
- package/account/Template.useInitialize.d.ts +12 -0
- package/account/Template.useInitialize.js +20 -0
- package/account/Template.useInitialize.js.map +1 -0
- package/account/i18n/index.d.ts +5 -5
- package/account/i18n/index.js +1 -1
- package/account/i18n/index.js.map +1 -1
- package/account/i18n/messages_defaultSet/types.d.ts +3 -0
- package/account/i18n/messages_defaultSet/types.js +26 -0
- package/account/i18n/messages_defaultSet/types.js.map +1 -0
- package/account/i18n/noJsx/GenericI18n_noJsx.d.ts +63 -0
- package/account/i18n/noJsx/GenericI18n_noJsx.js +2 -0
- package/account/i18n/noJsx/GenericI18n_noJsx.js.map +1 -0
- package/account/i18n/noJsx/getI18n.d.ts +41 -0
- package/account/i18n/noJsx/getI18n.js +207 -0
- package/account/i18n/noJsx/getI18n.js.map +1 -0
- package/account/i18n/noJsx/i18nBuilder.d.ts +18 -0
- package/account/i18n/noJsx/i18nBuilder.js +27 -0
- package/account/i18n/noJsx/i18nBuilder.js.map +1 -0
- package/account/i18n/noJsx/index.d.ts +3 -0
- package/account/i18n/noJsx/index.js +2 -0
- package/account/i18n/noJsx/index.js.map +1 -0
- package/account/i18n/withJsx/GenericI18n.d.ts +72 -0
- package/account/i18n/withJsx/GenericI18n.js +5 -0
- package/account/i18n/withJsx/GenericI18n.js.map +1 -0
- package/account/i18n/withJsx/i18nBuilder.d.ts +18 -0
- package/account/i18n/withJsx/i18nBuilder.js +27 -0
- package/account/i18n/withJsx/i18nBuilder.js.map +1 -0
- package/account/i18n/withJsx/index.d.ts +3 -0
- package/account/i18n/withJsx/index.js +2 -0
- package/account/i18n/withJsx/index.js.map +1 -0
- package/account/i18n/withJsx/useI18n.d.ts +27 -0
- package/account/i18n/{useI18n.js → withJsx/useI18n.js} +6 -4
- package/account/i18n/withJsx/useI18n.js.map +1 -0
- package/account/index.d.ts +1 -1
- package/account/index.js +1 -1
- package/account/index.js.map +1 -1
- package/account/pages/Totp.js +3 -2
- package/account/pages/Totp.js.map +1 -1
- package/bin/246.index.js +191 -191
- package/bin/499.index.js +252 -68
- package/bin/main.js +1 -1
- package/lib/kcSanitize/HtmlPolicyBuilder.d.ts +28 -0
- package/lib/kcSanitize/HtmlPolicyBuilder.js +209 -0
- package/lib/kcSanitize/HtmlPolicyBuilder.js.map +1 -0
- package/lib/kcSanitize/KcSanitizer.d.ts +12 -0
- package/lib/kcSanitize/KcSanitizer.js +46 -0
- package/lib/kcSanitize/KcSanitizer.js.map +1 -0
- package/lib/kcSanitize/KcSanitizerPolicy.d.ts +24 -0
- package/lib/kcSanitize/KcSanitizerPolicy.js +149 -0
- package/lib/kcSanitize/KcSanitizerPolicy.js.map +1 -0
- package/lib/kcSanitize/index.d.ts +1 -0
- package/lib/kcSanitize/index.js +5 -0
- package/lib/kcSanitize/index.js.map +1 -0
- package/login/KcContext/kcContextMocks.js +24 -6
- package/login/KcContext/kcContextMocks.js.map +1 -1
- package/login/Template.js +7 -7
- package/login/Template.js.map +1 -1
- package/login/{Template.useStylesAndScripts.d.ts → Template.useInitialize.d.ts} +1 -4
- package/login/{Template.useStylesAndScripts.js → Template.useInitialize.js} +5 -23
- package/login/Template.useInitialize.js.map +1 -0
- package/login/i18n/index.d.ts +5 -5
- package/login/i18n/index.js +1 -1
- package/login/i18n/index.js.map +1 -1
- package/login/i18n/messages_defaultSet/types.d.ts +3 -0
- package/login/i18n/messages_defaultSet/types.js +33 -0
- package/login/i18n/messages_defaultSet/types.js.map +1 -0
- package/login/i18n/noJsx/GenericI18n_noJsx.d.ts +63 -0
- package/login/i18n/noJsx/GenericI18n_noJsx.js +2 -0
- package/login/i18n/noJsx/GenericI18n_noJsx.js.map +1 -0
- package/login/i18n/noJsx/getI18n.d.ts +41 -0
- package/login/i18n/noJsx/getI18n.js +207 -0
- package/login/i18n/noJsx/getI18n.js.map +1 -0
- package/login/i18n/noJsx/i18nBuilder.d.ts +18 -0
- package/login/i18n/noJsx/i18nBuilder.js +27 -0
- package/login/i18n/noJsx/i18nBuilder.js.map +1 -0
- package/login/i18n/noJsx/index.d.ts +3 -0
- package/login/i18n/noJsx/index.js +2 -0
- package/login/i18n/noJsx/index.js.map +1 -0
- package/login/i18n/withJsx/GenericI18n.d.ts +72 -0
- package/login/i18n/withJsx/GenericI18n.js +5 -0
- package/login/i18n/withJsx/GenericI18n.js.map +1 -0
- package/login/i18n/withJsx/i18nBuilder.d.ts +18 -0
- package/login/i18n/withJsx/i18nBuilder.js +27 -0
- package/login/i18n/withJsx/i18nBuilder.js.map +1 -0
- package/login/i18n/withJsx/index.d.ts +3 -0
- package/login/i18n/withJsx/index.js +2 -0
- package/login/i18n/withJsx/index.js.map +1 -0
- package/login/i18n/withJsx/useI18n.d.ts +27 -0
- package/login/i18n/{useI18n.js → withJsx/useI18n.js} +6 -4
- package/login/i18n/withJsx/useI18n.js.map +1 -0
- package/login/index.d.ts +1 -1
- package/login/index.js +1 -1
- package/login/index.js.map +1 -1
- package/login/lib/useUserProfileForm.d.ts +1 -1
- package/login/lib/useUserProfileForm.js +2 -1
- package/login/lib/useUserProfileForm.js.map +1 -1
- package/login/pages/Error.js +2 -1
- package/login/pages/Error.js.map +1 -1
- package/login/pages/Info.js +4 -3
- package/login/pages/Info.js.map +1 -1
- package/login/pages/Login.js +4 -3
- package/login/pages/Login.js.map +1 -1
- package/login/pages/LoginConfigTotp.js +3 -2
- package/login/pages/LoginConfigTotp.js.map +1 -1
- package/login/pages/LoginOtp.js +2 -1
- package/login/pages/LoginOtp.js.map +1 -1
- package/login/pages/LoginPassword.js +2 -1
- package/login/pages/LoginPassword.js.map +1 -1
- package/login/pages/LoginRecoveryAuthnCodeInput.js +2 -1
- package/login/pages/LoginRecoveryAuthnCodeInput.js.map +1 -1
- package/login/pages/LoginResetPassword.js +2 -1
- package/login/pages/LoginResetPassword.js.map +1 -1
- package/login/pages/LoginUpdatePassword.js +3 -2
- package/login/pages/LoginUpdatePassword.js.map +1 -1
- package/login/pages/Register.js +2 -1
- package/login/pages/Register.js.map +1 -1
- package/package.json +110 -31
- package/src/account/KcContext/kcContextMocks.ts +49 -29
- package/src/account/Template.tsx +11 -32
- package/src/account/Template.useInitialize.ts +35 -0
- package/src/account/i18n/index.ts +5 -5
- package/src/account/i18n/messages_defaultSet/types.ts +30 -0
- package/src/account/i18n/noJsx/GenericI18n_noJsx.ts +64 -0
- package/src/account/i18n/noJsx/getI18n.tsx +341 -0
- package/src/account/i18n/noJsx/i18nBuilder.ts +117 -0
- package/src/account/i18n/noJsx/index.ts +3 -0
- package/src/account/i18n/withJsx/GenericI18n.tsx +81 -0
- package/src/account/i18n/withJsx/i18nBuilder.ts +117 -0
- package/src/account/i18n/withJsx/index.ts +3 -0
- package/src/{login/i18n → account/i18n/withJsx}/useI18n.tsx +43 -11
- package/src/account/index.ts +1 -1
- package/src/account/pages/Totp.tsx +3 -2
- package/src/bin/initialize-account-theme/src/multi-page/i18n.ts +10 -3
- package/src/bin/keycloakify/generateFtl/kcContextDeclarationTemplate.ftl +15 -0
- package/src/bin/keycloakify/generateResources/generateMessageProperties.ts +371 -121
- package/src/bin/keycloakify/generateResources/generateResources.ts +8 -6
- package/src/bin/keycloakify/generateResources/generateResourcesForMainTheme.ts +61 -29
- package/src/bin/keycloakify/generateResources/generateResourcesForThemeVariant.ts +15 -9
- package/src/lib/kcSanitize/HtmlPolicyBuilder.ts +252 -0
- package/src/lib/kcSanitize/KcSanitizer.ts +60 -0
- package/src/lib/kcSanitize/KcSanitizerPolicy.ts +294 -0
- package/src/lib/kcSanitize/index.ts +5 -0
- package/src/login/KcContext/kcContextMocks.ts +54 -29
- package/src/login/Template.tsx +11 -17
- package/src/login/{Template.useStylesAndScripts.ts → Template.useInitialize.ts} +5 -29
- package/src/login/i18n/index.ts +5 -5
- package/src/login/i18n/messages_defaultSet/types.ts +37 -0
- package/src/login/i18n/noJsx/GenericI18n_noJsx.ts +64 -0
- package/src/login/i18n/noJsx/getI18n.tsx +341 -0
- package/src/login/i18n/noJsx/i18nBuilder.ts +117 -0
- package/src/login/i18n/noJsx/index.ts +3 -0
- package/src/login/i18n/withJsx/GenericI18n.tsx +81 -0
- package/src/login/i18n/withJsx/i18nBuilder.ts +117 -0
- package/src/login/i18n/withJsx/index.ts +3 -0
- package/src/{account/i18n → login/i18n/withJsx}/useI18n.tsx +43 -11
- package/src/login/index.ts +1 -1
- package/src/login/lib/useUserProfileForm.tsx +3 -2
- package/src/login/pages/Error.tsx +2 -1
- package/src/login/pages/Info.tsx +13 -10
- package/src/login/pages/Login.tsx +4 -3
- package/src/login/pages/LoginConfigTotp.tsx +3 -2
- package/src/login/pages/LoginOtp.tsx +2 -1
- package/src/login/pages/LoginPassword.tsx +2 -1
- package/src/login/pages/LoginRecoveryAuthnCodeInput.tsx +2 -1
- package/src/login/pages/LoginResetPassword.tsx +2 -1
- package/src/login/pages/LoginUpdatePassword.tsx +3 -2
- package/src/login/pages/Register.tsx +2 -1
- package/src/tools/useInsertScriptTags.ts +1 -1
- package/src/tools/vendor/dompurify.ts +3 -0
- package/stories/intro/intro.stories.tsx +0 -1
- package/tools/useInsertScriptTags.d.ts +1 -1
- package/tools/vendor/dompurify.d.ts +2 -0
- package/tools/vendor/dompurify.js +2 -0
- package/account/i18n/GenericI18n.d.ts +0 -6
- package/account/i18n/GenericI18n.js +0 -2
- package/account/i18n/GenericI18n.js.map +0 -1
- package/account/i18n/i18n.d.ts +0 -87
- package/account/i18n/i18n.js +0 -111
- package/account/i18n/i18n.js.map +0 -1
- package/account/i18n/useI18n.d.ts +0 -14
- package/account/i18n/useI18n.js.map +0 -1
- package/login/Template.useStylesAndScripts.js.map +0 -1
- package/login/i18n/GenericI18n.d.ts +0 -6
- package/login/i18n/GenericI18n.js +0 -2
- package/login/i18n/GenericI18n.js.map +0 -1
- package/login/i18n/i18n.d.ts +0 -87
- package/login/i18n/i18n.js +0 -113
- package/login/i18n/i18n.js.map +0 -1
- package/login/i18n/useI18n.d.ts +0 -14
- package/login/i18n/useI18n.js.map +0 -1
- package/src/account/i18n/GenericI18n.tsx +0 -6
- package/src/account/i18n/i18n.tsx +0 -250
- package/src/login/i18n/GenericI18n.tsx +0 -6
- package/src/login/i18n/i18n.tsx +0 -252
@@ -1,6 +1,6 @@
|
|
1
1
|
import { type ThemeType, FALLBACK_LANGUAGE_TAG } from "../../shared/constants";
|
2
2
|
import { crawl } from "../../tools/crawl";
|
3
|
-
import { join as pathJoin } from "path";
|
3
|
+
import { join as pathJoin, dirname as pathDirname } from "path";
|
4
4
|
import { symToStr } from "tsafe/symToStr";
|
5
5
|
import * as recast from "recast";
|
6
6
|
import * as babelParser from "@babel/parser";
|
@@ -10,12 +10,27 @@ import { escapeStringForPropertiesFile } from "../../tools/escapeStringForProper
|
|
10
10
|
import { getThisCodebaseRootDirPath } from "../../tools/getThisCodebaseRootDirPath";
|
11
11
|
import * as fs from "fs";
|
12
12
|
import { assert } from "tsafe/assert";
|
13
|
+
import type { BuildContext } from "../../shared/buildContext";
|
14
|
+
import { getAbsoluteAndInOsFormatPath } from "../../tools/getAbsoluteAndInOsFormatPath";
|
13
15
|
|
14
|
-
export
|
16
|
+
export type BuildContextLike = {
|
17
|
+
themeNames: string[];
|
15
18
|
themeSrcDirPath: string;
|
19
|
+
};
|
20
|
+
|
21
|
+
assert<BuildContext extends BuildContextLike ? true : false>();
|
22
|
+
|
23
|
+
export function generateMessageProperties(params: {
|
24
|
+
buildContext: BuildContextLike;
|
16
25
|
themeType: ThemeType;
|
17
|
-
}): {
|
18
|
-
|
26
|
+
}): {
|
27
|
+
languageTags: string[];
|
28
|
+
writeMessagePropertiesFiles: (params: {
|
29
|
+
messageDirPath: string;
|
30
|
+
themeName: string;
|
31
|
+
}) => void;
|
32
|
+
} {
|
33
|
+
const { buildContext, themeType } = params;
|
19
34
|
|
20
35
|
const baseMessagesDirPath = pathJoin(
|
21
36
|
getThisCodebaseRootDirPath(),
|
@@ -25,51 +40,49 @@ export function generateMessageProperties(params: {
|
|
25
40
|
"messages_defaultSet"
|
26
41
|
);
|
27
42
|
|
28
|
-
const
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
.toString("utf8")
|
41
|
-
.split(/\r?\n/);
|
42
|
-
|
43
|
-
let messagesJson = "{";
|
44
|
-
|
45
|
-
let isInDeclaration = false;
|
46
|
-
|
47
|
-
for (const line of lines) {
|
48
|
-
if (!isInDeclaration) {
|
49
|
-
if (line.startsWith("const messages")) {
|
50
|
-
isInDeclaration = true;
|
51
|
-
}
|
43
|
+
const messages_defaultSet_by_languageTag_defaultSet: {
|
44
|
+
[languageTag_defaultSet: string]: Record<string, string>;
|
45
|
+
} = Object.fromEntries(
|
46
|
+
fs
|
47
|
+
.readdirSync(baseMessagesDirPath)
|
48
|
+
.filter(basename => basename !== "index.ts" && basename !== "types.ts")
|
49
|
+
.map(basename => ({
|
50
|
+
languageTag: basename.replace(/\.ts$/, ""),
|
51
|
+
filePath: pathJoin(baseMessagesDirPath, basename)
|
52
|
+
}))
|
53
|
+
.map(({ languageTag, filePath }) => {
|
54
|
+
const lines = fs.readFileSync(filePath).toString("utf8").split(/\r?\n/);
|
52
55
|
|
53
|
-
|
54
|
-
|
56
|
+
let messagesJson = "{";
|
57
|
+
|
58
|
+
let isInDeclaration = false;
|
55
59
|
|
56
|
-
|
57
|
-
|
58
|
-
|
60
|
+
for (const line of lines) {
|
61
|
+
if (!isInDeclaration) {
|
62
|
+
if (line.startsWith("const messages")) {
|
63
|
+
isInDeclaration = true;
|
59
64
|
}
|
60
65
|
|
61
|
-
|
66
|
+
continue;
|
62
67
|
}
|
63
68
|
|
64
|
-
|
69
|
+
if (line.startsWith("}")) {
|
70
|
+
messagesJson += "}";
|
71
|
+
break;
|
72
|
+
}
|
65
73
|
|
66
|
-
|
67
|
-
}
|
68
|
-
|
74
|
+
messagesJson += line;
|
75
|
+
}
|
76
|
+
|
77
|
+
const messages = JSON.parse(messagesJson) as Record<string, string>;
|
78
|
+
|
79
|
+
return [languageTag, messages];
|
80
|
+
})
|
81
|
+
);
|
69
82
|
|
70
83
|
const { i18nTsFilePath } = (() => {
|
71
84
|
let files = crawl({
|
72
|
-
dirPath: pathJoin(themeSrcDirPath, themeType),
|
85
|
+
dirPath: pathJoin(buildContext.themeSrcDirPath, themeType),
|
73
86
|
returnedPathsType: "absolute"
|
74
87
|
});
|
75
88
|
|
@@ -88,7 +101,7 @@ export function generateMessageProperties(params: {
|
|
88
101
|
files = files.sort((a, b) => a.length - b.length);
|
89
102
|
|
90
103
|
files = files.filter(file =>
|
91
|
-
fs.readFileSync(file).toString("utf8").includes("
|
104
|
+
fs.readFileSync(file).toString("utf8").includes("i18nBuilder")
|
92
105
|
);
|
93
106
|
|
94
107
|
const i18nTsFilePath: string | undefined = files[0];
|
@@ -96,97 +109,334 @@ export function generateMessageProperties(params: {
|
|
96
109
|
return { i18nTsFilePath };
|
97
110
|
})();
|
98
111
|
|
99
|
-
const
|
100
|
-
(
|
101
|
-
|
102
|
-
|
112
|
+
const i18nTsRoot = (() => {
|
113
|
+
if (i18nTsFilePath === undefined) {
|
114
|
+
return undefined;
|
115
|
+
}
|
116
|
+
const root = recastParseTs(i18nTsFilePath);
|
117
|
+
return root;
|
118
|
+
})();
|
119
|
+
|
120
|
+
const messages_defaultSet_by_languageTag_notInDefaultSet:
|
121
|
+
| { [languageTag_notInDefaultSet: string]: Record<string, string> }
|
122
|
+
| undefined = (() => {
|
123
|
+
if (i18nTsRoot === undefined) {
|
124
|
+
return undefined;
|
125
|
+
}
|
126
|
+
|
127
|
+
let extraLanguageEntryByLanguageTag: Record<
|
128
|
+
string,
|
129
|
+
{ label: string; path: string }
|
130
|
+
> = {};
|
131
|
+
|
132
|
+
recast.visit(i18nTsRoot, {
|
133
|
+
visitCallExpression: function (path) {
|
134
|
+
const node = path.node;
|
135
|
+
|
136
|
+
// Check if the callee is a MemberExpression with property 'withExtraLanguages'
|
137
|
+
if (
|
138
|
+
node.callee.type === "MemberExpression" &&
|
139
|
+
node.callee.property.type === "Identifier" &&
|
140
|
+
node.callee.property.name === "withExtraLanguages"
|
141
|
+
) {
|
142
|
+
const arg = node.arguments[0];
|
143
|
+
if (arg && arg.type === "ObjectExpression") {
|
144
|
+
// Iterate over the properties of the object
|
145
|
+
arg.properties.forEach(prop => {
|
146
|
+
if (
|
147
|
+
prop.type === "ObjectProperty" &&
|
148
|
+
prop.key.type === "Identifier"
|
149
|
+
) {
|
150
|
+
const lang = prop.key.name;
|
151
|
+
const value = prop.value;
|
152
|
+
|
153
|
+
if (value.type === "ObjectExpression") {
|
154
|
+
let label: string | undefined = undefined;
|
155
|
+
let pathStr: string | undefined = undefined;
|
156
|
+
|
157
|
+
// Iterate over the properties of the language object
|
158
|
+
value.properties.forEach(p => {
|
159
|
+
if (
|
160
|
+
p.type === "ObjectProperty" &&
|
161
|
+
p.key.type === "Identifier"
|
162
|
+
) {
|
163
|
+
if (
|
164
|
+
p.key.name === "label" &&
|
165
|
+
p.value.type === "StringLiteral"
|
166
|
+
) {
|
167
|
+
label = p.value.value;
|
168
|
+
}
|
169
|
+
if (
|
170
|
+
p.key.name === "getMessages" &&
|
171
|
+
(p.value.type ===
|
172
|
+
"ArrowFunctionExpression" ||
|
173
|
+
p.value.type === "FunctionExpression")
|
174
|
+
) {
|
175
|
+
// Extract the import path from the function body
|
176
|
+
const body = p.value.body;
|
177
|
+
if (
|
178
|
+
body.type === "CallExpression" &&
|
179
|
+
body.callee.type === "Import"
|
180
|
+
) {
|
181
|
+
const importArg = body.arguments[0];
|
182
|
+
if (
|
183
|
+
importArg.type === "StringLiteral"
|
184
|
+
) {
|
185
|
+
pathStr = importArg.value;
|
186
|
+
}
|
187
|
+
} else if (
|
188
|
+
body.type === "BlockStatement"
|
189
|
+
) {
|
190
|
+
// If the function body is a block (e.g., function with braces {})
|
191
|
+
// Look for return statement
|
192
|
+
body.body.forEach(statement => {
|
193
|
+
if (
|
194
|
+
statement.type ===
|
195
|
+
"ReturnStatement" &&
|
196
|
+
statement.argument &&
|
197
|
+
statement.argument.type ===
|
198
|
+
"CallExpression" &&
|
199
|
+
statement.argument.callee
|
200
|
+
.type === "Import"
|
201
|
+
) {
|
202
|
+
const importArg =
|
203
|
+
statement.argument
|
204
|
+
.arguments[0];
|
205
|
+
if (
|
206
|
+
importArg.type ===
|
207
|
+
"StringLiteral"
|
208
|
+
) {
|
209
|
+
pathStr = importArg.value;
|
210
|
+
}
|
211
|
+
}
|
212
|
+
});
|
213
|
+
}
|
214
|
+
}
|
215
|
+
}
|
216
|
+
});
|
217
|
+
|
218
|
+
if (label && pathStr) {
|
219
|
+
extraLanguageEntryByLanguageTag[lang] = {
|
220
|
+
label,
|
221
|
+
path: pathStr
|
222
|
+
};
|
223
|
+
}
|
224
|
+
}
|
225
|
+
}
|
226
|
+
});
|
227
|
+
}
|
228
|
+
|
229
|
+
return false; // Stop traversing this path
|
230
|
+
}
|
231
|
+
|
232
|
+
this.traverse(path); // Continue traversing other paths
|
103
233
|
}
|
234
|
+
});
|
235
|
+
|
236
|
+
const messages_defaultSet_by_languageTag_notInDefaultSet = Object.fromEntries(
|
237
|
+
Object.entries(extraLanguageEntryByLanguageTag).map(
|
238
|
+
([languageTag, { path: relativePathWithoutExt }]) => [
|
239
|
+
languageTag,
|
240
|
+
(() => {
|
241
|
+
const filePath = getAbsoluteAndInOsFormatPath({
|
242
|
+
pathIsh: relativePathWithoutExt.endsWith(".ts")
|
243
|
+
? relativePathWithoutExt
|
244
|
+
: `${relativePathWithoutExt}.ts`,
|
245
|
+
cwd: pathDirname(i18nTsFilePath)
|
246
|
+
});
|
104
247
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
248
|
+
const root = recastParseTs(filePath);
|
249
|
+
|
250
|
+
let declarationCode: string | undefined = "";
|
251
|
+
|
252
|
+
recast.visit(root, {
|
253
|
+
visitVariableDeclarator: function (path) {
|
254
|
+
const node = path.node;
|
255
|
+
|
256
|
+
// Check if the variable name is 'messages'
|
257
|
+
if (
|
258
|
+
node.id.type === "Identifier" &&
|
259
|
+
node.id.name === "messages"
|
260
|
+
) {
|
261
|
+
// Ensure there is an initializer
|
262
|
+
if (node.init) {
|
263
|
+
// Generate code from the initializer, preserving comments
|
264
|
+
declarationCode = recast
|
265
|
+
.print(node.init)
|
266
|
+
.code.replace(/}.*$/, "}");
|
267
|
+
}
|
268
|
+
return false; // Stop traversing this path
|
269
|
+
}
|
270
|
+
|
271
|
+
this.traverse(path); // Continue traversing other paths
|
272
|
+
}
|
273
|
+
});
|
274
|
+
|
275
|
+
assert(
|
276
|
+
declarationCode !== undefined,
|
277
|
+
`${filePath} does not contain a 'messages' variable declaration`
|
278
|
+
);
|
279
|
+
|
280
|
+
let messages: Record<string, string> = {};
|
281
|
+
|
282
|
+
try {
|
283
|
+
eval(`${symToStr({ messages })} = ${declarationCode};`);
|
284
|
+
} catch {
|
285
|
+
throw new Error(
|
286
|
+
`The declaration of 'message' in ${filePath} cannot be statically evaluated: ${declarationCode}`
|
287
|
+
);
|
288
|
+
}
|
289
|
+
|
290
|
+
return messages;
|
291
|
+
})()
|
292
|
+
]
|
293
|
+
)
|
294
|
+
);
|
295
|
+
|
296
|
+
return messages_defaultSet_by_languageTag_notInDefaultSet;
|
297
|
+
})();
|
298
|
+
|
299
|
+
const messages_defaultSet_by_languageTag = {
|
300
|
+
...messages_defaultSet_by_languageTag_defaultSet,
|
301
|
+
...messages_defaultSet_by_languageTag_notInDefaultSet
|
302
|
+
};
|
303
|
+
|
304
|
+
const messages_themeDefined_by_languageTag:
|
305
|
+
| {
|
306
|
+
[languageTag: string]:
|
307
|
+
| Record<string, string | Record<string, string>>
|
308
|
+
| undefined;
|
309
|
+
}
|
310
|
+
| undefined = (() => {
|
311
|
+
if (i18nTsRoot === undefined) {
|
312
|
+
return undefined;
|
313
|
+
}
|
314
|
+
|
315
|
+
let firstArgumentCode: string | undefined = undefined;
|
316
|
+
|
317
|
+
recast.visit(i18nTsRoot, {
|
318
|
+
visitCallExpression: function (path) {
|
319
|
+
const node = path.node;
|
320
|
+
|
321
|
+
if (
|
322
|
+
node.callee.type === "MemberExpression" &&
|
323
|
+
node.callee.property.type === "Identifier" &&
|
324
|
+
node.callee.property.name === "withCustomTranslations"
|
325
|
+
) {
|
326
|
+
firstArgumentCode = babelGenerate(node.arguments[0] as any).code;
|
327
|
+
return false;
|
114
328
|
}
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
329
|
+
|
330
|
+
this.traverse(path);
|
331
|
+
}
|
332
|
+
});
|
333
|
+
|
334
|
+
if (firstArgumentCode === undefined) {
|
335
|
+
return undefined;
|
336
|
+
}
|
337
|
+
|
338
|
+
let messages_themeDefined_by_languageTag: {
|
339
|
+
[languageTag: string]: Record<string, string | Record<string, string>>;
|
340
|
+
} = {};
|
341
|
+
|
342
|
+
try {
|
343
|
+
eval(
|
344
|
+
`${symToStr({ messages_themeDefined_by_languageTag })} = ${firstArgumentCode}`
|
345
|
+
);
|
346
|
+
} catch {
|
347
|
+
console.warn(
|
348
|
+
[
|
349
|
+
"WARNING: The argument of withCustomTranslations can't be statically evaluated!",
|
350
|
+
"This needs to be fixed refer to the documentation: https://docs.keycloakify.dev/i18n",
|
351
|
+
firstArgumentCode
|
352
|
+
].join(" ")
|
353
|
+
);
|
354
|
+
return undefined;
|
355
|
+
}
|
356
|
+
|
357
|
+
return messages_themeDefined_by_languageTag;
|
358
|
+
})();
|
359
|
+
|
360
|
+
const languageTags = Object.keys(messages_defaultSet_by_languageTag);
|
361
|
+
|
362
|
+
return {
|
363
|
+
languageTags,
|
364
|
+
writeMessagePropertiesFiles: ({ messageDirPath, themeName }) => {
|
365
|
+
for (const languageTag of languageTags) {
|
366
|
+
const messages = {
|
367
|
+
...messages_defaultSet_by_languageTag[languageTag]
|
368
|
+
};
|
369
|
+
|
370
|
+
add_theme_defined_messages: {
|
371
|
+
if (messages_themeDefined_by_languageTag === undefined) {
|
372
|
+
break add_theme_defined_messages;
|
373
|
+
}
|
374
|
+
|
375
|
+
let messages_themeDefined =
|
376
|
+
messages_themeDefined_by_languageTag[languageTag];
|
377
|
+
|
378
|
+
if (messages_themeDefined === undefined) {
|
379
|
+
messages_themeDefined =
|
380
|
+
messages_themeDefined_by_languageTag[FALLBACK_LANGUAGE_TAG];
|
129
381
|
}
|
382
|
+
if (messages_themeDefined === undefined) {
|
383
|
+
messages_themeDefined =
|
384
|
+
messages_themeDefined_by_languageTag[
|
385
|
+
Object.keys(messages_themeDefined_by_languageTag)[0]
|
386
|
+
];
|
387
|
+
}
|
388
|
+
if (messages_themeDefined === undefined) {
|
389
|
+
break add_theme_defined_messages;
|
390
|
+
}
|
391
|
+
|
392
|
+
for (const [key, messageOrMessageByThemeName] of Object.entries(
|
393
|
+
messages_themeDefined
|
394
|
+
)) {
|
395
|
+
const message = (() => {
|
396
|
+
if (typeof messageOrMessageByThemeName === "string") {
|
397
|
+
return messageOrMessageByThemeName;
|
398
|
+
}
|
130
399
|
|
131
|
-
|
400
|
+
const message = messageOrMessageByThemeName[themeName];
|
401
|
+
|
402
|
+
assert(message !== undefined);
|
403
|
+
|
404
|
+
return message;
|
405
|
+
})();
|
406
|
+
|
407
|
+
messages[key] = message;
|
408
|
+
}
|
132
409
|
}
|
133
|
-
});
|
134
410
|
|
135
|
-
|
411
|
+
const propertiesFileSource = [
|
412
|
+
"",
|
413
|
+
...Object.entries(messages).map(
|
414
|
+
([key, value]) => `${key}=${escapeStringForPropertiesFile(value)}`
|
415
|
+
),
|
416
|
+
""
|
417
|
+
].join("\n");
|
136
418
|
|
137
|
-
|
138
|
-
[languageTag: string]: Record<string, string>;
|
139
|
-
} = {};
|
419
|
+
fs.mkdirSync(messageDirPath, { recursive: true });
|
140
420
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
);
|
145
|
-
} catch {
|
146
|
-
console.warn(
|
147
|
-
[
|
148
|
-
"WARNING: Make sure the messageBundle your provided as argument of createUseI18n can be statically evaluated.",
|
149
|
-
"This is important because we need to put your i18n messages in messages_*.properties files",
|
150
|
-
"or they won't be available server side.",
|
151
|
-
"\n",
|
152
|
-
"The following code could not be evaluated:",
|
153
|
-
"\n",
|
154
|
-
messageBundleDeclarationTsCode
|
155
|
-
].join(" ")
|
421
|
+
fs.writeFileSync(
|
422
|
+
pathJoin(messageDirPath, `messages_${languageTag}.properties`),
|
423
|
+
Buffer.from(propertiesFileSource, "utf8")
|
156
424
|
);
|
157
425
|
}
|
426
|
+
}
|
427
|
+
};
|
428
|
+
}
|
158
429
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
messageBundle[FALLBACK_LANGUAGE_TAG] ??
|
172
|
-
messageBundle[Object.keys(messageBundle)[0]] ??
|
173
|
-
{})
|
174
|
-
}
|
175
|
-
])
|
176
|
-
);
|
177
|
-
|
178
|
-
const messageProperties: { languageTag: string; propertiesFileSource: string }[] =
|
179
|
-
Object.entries(mergedMessageBundle).map(([languageTag, messages]) => ({
|
180
|
-
languageTag,
|
181
|
-
propertiesFileSource: [
|
182
|
-
"",
|
183
|
-
...(themeType !== "account" ? ["parent=base"] : []),
|
184
|
-
...Object.entries(messages).map(
|
185
|
-
([key, value]) => `${key}=${escapeStringForPropertiesFile(value)}`
|
186
|
-
),
|
187
|
-
""
|
188
|
-
].join("\n")
|
189
|
-
}));
|
190
|
-
|
191
|
-
return messageProperties;
|
430
|
+
function recastParseTs(filePath: string): recast.types.ASTNode {
|
431
|
+
return recast.parse(fs.readFileSync(filePath).toString("utf8"), {
|
432
|
+
parser: {
|
433
|
+
parse: (code: string) =>
|
434
|
+
babelParser.parse(code, {
|
435
|
+
sourceType: "module",
|
436
|
+
plugins: ["typescript"]
|
437
|
+
}),
|
438
|
+
generator: babelGenerate,
|
439
|
+
types: babelTypes
|
440
|
+
}
|
441
|
+
});
|
192
442
|
}
|
@@ -26,17 +26,19 @@ export async function generateResources(params: {
|
|
26
26
|
rmSync(resourcesDirPath, { recursive: true });
|
27
27
|
}
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
const { writeMessagePropertiesFilesForThemeVariant } =
|
30
|
+
await generateResourcesForMainTheme({
|
31
|
+
resourcesDirPath,
|
32
|
+
themeName,
|
33
|
+
buildContext
|
34
|
+
});
|
34
35
|
|
35
36
|
for (const themeVariantName of themeVariantNames) {
|
36
37
|
generateResourcesForThemeVariant({
|
37
38
|
resourcesDirPath,
|
38
39
|
themeName,
|
39
|
-
themeVariantName
|
40
|
+
themeVariantName,
|
41
|
+
writeMessagePropertiesFiles: writeMessagePropertiesFilesForThemeVariant
|
40
42
|
});
|
41
43
|
}
|
42
44
|
}
|